Skip to content

Nomad Deployment Examples ​

Copy-and-paste examples for pfy nomad: single deploys, stack deploys, per-environment scripts, CI pipelines, and rollbacks. Every example renders the job from the deployment spec stored in the Manager and targets it with --env <alias>, a project.yaml alias managed by pfy env. Outputs shown are abridged.

Table of Contents ​


Basic Examples ​

Deploy with Explicit Tag ​

bash
# Deploy the prod environment's job with image tag v1.2.3
pfy nomad deploy --env prod --tag v1.2.3 --yes

Output:

Rendered myapp job to nomad/myapp.nomad.hcl (spec 3f9a2c…)
Deploying spec 9c1d0e… → 3f9a2c…
✓ Rendered job is valid
Running 'nomad job run nomad/myapp.nomad.hcl'...

✓ Job deployed successfully

The Deploying spec line shows the spec hash stamped on the running job and the new one. It reads Re-deploying spec … (no spec change since last apply) when only the image tag changed, and just Deploying spec … when the job is not running yet or Nomad could not be asked.

Render Without Deploying ​

bash
# Write the rendered job to the committed artifact path (ci.nomad_file)
pfy nomad render --env prod --tag v1.2.3

# Or print it to stdout
pfy nomad render --env prod --tag v1.2.3 --out -

Preview the Rendered Job ​

bash
# Print the render without writing, validating, or deploying
pfy nomad deploy --env prod --tag v1.2.3 --dry-run

Adopt a Hand-Written Job File ​

bash
# One-time migration: extract the spec from an existing job file
pfy nomad adopt nomad/legacy/manager.nomad --env prod --dry-run   # preview
pfy nomad adopt nomad/legacy/manager.nomad --env prod             # write the spec

Version Management Integration ​

Bump and Deploy ​

bash
# Bump version in project.yaml
pfy version bump --part minor

# Deploy using the bumped version as the image tag
pfy nomad deploy --env prod --use-project-version --yes

Output:

Version updated: 1.2.3 → 1.3.0
Configuration saved to project.yaml

Rendered myapp job to nomad/myapp.nomad.hcl (spec 3f9a2c…)
Re-deploying spec 3f9a2c… (no spec change since last apply)
✓ Rendered job is valid
Running 'nomad job run nomad/myapp.nomad.hcl'...

✓ Job deployed successfully

Set Specific Version and Deploy to Every Environment ​

bash
# Set version to 2.0.0
pfy version set --version 2.0.0

# Deploy each environment alias with the new version
for env in dev staging prod; do
  pfy nomad deploy --env $env --use-project-version --yes
done

Stack Deployments ​

An application is a stack: managed data stores (postgres/redis), their backup jobs, and the services that consume them. --stack applies all of it in dependency order, waiting for each stage to become healthy.

Deploy the Full Stack ​

bash
pfy nomad deploy --stack \
  --env prod \
  --app myapp --project my-saas \
  --tag v1.3.0 \
  --install install.yaml \
  --yes

Output (abridged):

Generated a credential for main at <nomad var path>
Rendered myapp--main (data store) to deploy/myapp--main.nomad.hcl
Running 'nomad job run deploy/myapp--main.nomad.hcl'...
Waiting for myapp--main (data store) to become healthy...
✓ myapp--main is healthy
Rendered myapp (service, with prestart migration) to deploy/myapp.nomad.hcl
Running 'nomad job run deploy/myapp.nomad.hcl'...

✓ Stack applied (3 jobs)

Only the Data Stores ​

bash
pfy nomad deploy --stack --env prod --app myapp --project my-saas --only-data --yes

One Service of the Stack ​

bash
pfy nomad deploy --stack --env prod --app myapp --project my-saas --service api --yes

Staged Deployment with Validation ​

bash
#!/bin/bash
# deploy-with-validation.sh

ENVS=("dev" "staging" "prod")

for env in "${ENVS[@]}"; do
  echo "Planning $env..."
  pfy nomad deploy --env $env --use-project-version --plan-only

  read -p "Deploy $env? (y/n) " -n 1 -r
  echo
  if [[ $REPLY =~ ^[Yy]$ ]]; then
    pfy nomad deploy --env $env --use-project-version --yes
  fi
done

Environment-Specific Deployments ​

Each environment is one project.yaml alias resolving to its own deployment spec; there is no per-environment job file to maintain.

Development Environment ​

bash
# Deploy latest development build
pfy nomad deploy --env dev --tag dev-latest --yes

# Or use the branch name
BRANCH=$(git rev-parse --abbrev-ref HEAD)
pfy nomad deploy --env dev --tag dev-$BRANCH --yes

Staging Environment ​

bash
# Deploy a specific version to staging
pfy nomad deploy --env staging --tag v1.3.0 --yes

# Or use the project version
pfy nomad deploy --env staging --use-project-version --yes

Production Environment ​

bash
# Always plan first in production
pfy nomad deploy --env prod --tag v1.3.0 --plan-only

# Review output carefully, then deploy
pfy nomad deploy --env prod --tag v1.3.0 --yes

Dedicated Tenants ​

bash
# The shared deployment
pfy nomad deploy --env prod --tag v1.3.0 --yes

# A tenant's dedicated deployment (job name myapp--acme, server-derived)
pfy nomad deploy --env prod --tenant acme --tag v1.3.0 --yes

Environment Deployment Script ​

bash
#!/bin/bash
# deploy-env.sh <environment> <version>

ENV=$1
VERSION=$2

if [ -z "$ENV" ] || [ -z "$VERSION" ]; then
  echo "Usage: $0 <dev|staging|prod> <version>"
  exit 1
fi

if [ "$ENV" = "prod" ]; then
  echo "Planning production deployment..."
  pfy nomad deploy --env $ENV --tag $VERSION --plan-only

  read -p "Proceed with production deployment? (yes/no) " CONFIRM
  if [ "$CONFIRM" != "yes" ]; then
    echo "Deployment cancelled"
    exit 0
  fi
fi

echo "Deploying to $ENV..."
pfy nomad deploy --env $ENV --tag $VERSION --yes

echo "✓ Deployment to $ENV complete"

CI/CD Pipeline Examples ​

GitHub Actions Workflow ​

yaml
name: Deploy to Nomad

on:
  push:
    tags:
      - "v*"
  workflow_dispatch:
    inputs:
      environment:
        description: "Deployment environment"
        required: true
        default: "staging"
        type: choice
        options:
          - dev
          - staging
          - prod

env:
  NOMAD_ADDR: ${{ secrets.NOMAD_ADDR }}
  NOMAD_TOKEN: ${{ secrets.NOMAD_TOKEN }}
  PFY_MANAGER_URL: ${{ secrets.PFY_MANAGER_URL }}
  PFY_MANAGER_TOKEN: ${{ secrets.PFY_MANAGER_TOKEN }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install pfy CLI
        run: |
          PFY_VERSION=$(curl -fsSL https://api.github.com/repos/ProductifyFW/cli/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
          curl -fsSLO "https://github.com/ProductifyFW/cli/releases/download/v${PFY_VERSION}/pfy_${PFY_VERSION}_linux_amd64.tar.gz"
          curl -fsSLO "https://github.com/ProductifyFW/cli/releases/download/v${PFY_VERSION}/checksums.txt"
          grep "pfy_${PFY_VERSION}_linux_amd64.tar.gz" checksums.txt | sha256sum -c -
          tar -xzf "pfy_${PFY_VERSION}_linux_amd64.tar.gz" pfy
          sudo mv pfy /usr/local/bin/pfy

      - name: Extract version
        id: version
        run: |
          if [[ "${{ github.ref }}" == refs/tags/* ]]; then
            VERSION=${GITHUB_REF#refs/tags/v}
          else
            VERSION=$(pfy version show)
          fi
          echo "version=$VERSION" >> $GITHUB_OUTPUT

      - name: Deploy to staging
        if: github.event.inputs.environment == 'staging' || github.ref_type == 'tag'
        run: |
          pfy --ci nomad deploy \
            --env staging \
            --tag v${{ steps.version.outputs.version }} \
            --yes

      - name: Deploy to production
        if: github.event.inputs.environment == 'prod'
        run: |
          # Plan first
          pfy --ci nomad deploy \
            --env prod \
            --tag v${{ steps.version.outputs.version }} \
            --plan-only

          # Deploy
          pfy --ci nomad deploy \
            --env prod \
            --tag v${{ steps.version.outputs.version }} \
            --yes

GitLab CI/CD Pipeline ​

The jobs also need NOMAD_TOKEN, PFY_MANAGER_URL, and PFY_MANAGER_TOKEN as CI/CD variables, and an image with curl and tar.

yaml
stages:
  - build
  - deploy:dev
  - deploy:staging
  - deploy:prod

variables:
  NOMAD_ADDR: $NOMAD_SERVER_URL
  PFY_VERSION: "2.0.0" # pin the pfy release to install

before_script:
  - curl -fsSLO "https://github.com/ProductifyFW/cli/releases/download/v${PFY_VERSION}/pfy_${PFY_VERSION}_linux_amd64.tar.gz"
  - tar -xzf "pfy_${PFY_VERSION}_linux_amd64.tar.gz" pfy
  - mv pfy /usr/local/bin/pfy

# Deploy to development on every commit
deploy:dev:
  stage: deploy:dev
  script:
    - VERSION=$(git rev-parse --short HEAD)
    - pfy --ci nomad deploy --env dev --tag dev-$VERSION --yes
  environment:
    name: development
  only:
    - main

# Deploy to staging on tags
deploy:staging:
  stage: deploy:staging
  script:
    - VERSION=${CI_COMMIT_TAG#v}
    - pfy --ci nomad deploy --env staging --tag v$VERSION --yes
  environment:
    name: staging
  only:
    - tags

# Deploy to production manually
deploy:prod:
  stage: deploy:prod
  script:
    - VERSION=${CI_COMMIT_TAG#v}
    - pfy --ci nomad deploy --env prod --tag v$VERSION --plan-only
    - pfy --ci nomad deploy --env prod --tag v$VERSION --yes
  environment:
    name: production
  only:
    - tags
  when: manual

Rollback Scenarios ​

Quick Rollback ​

bash
# Rollback to the previous image tag
pfy nomad deploy --env prod --tag v1.2.3 --yes

Rollback with Git ​

bash
# Find previous version
git log --oneline project.yaml | head -5

# Checkout previous version
git show HEAD~1:project.yaml | grep version

# Rollback
pfy nomad deploy --env prod --tag v1.2.3 --yes

Rolling back the tag does not roll back spec changes; check pfy deploy diff --env prod and pfy deployment get --env prod when the regression is not image-related.

Automated Rollback Script ​

bash
#!/bin/bash
# rollback.sh <environment> <previous-version>

ENV=$1
PREV_VERSION=$2

if [ -z "$ENV" ] || [ -z "$PREV_VERSION" ]; then
  echo "Usage: $0 <environment> <version>"
  exit 1
fi

echo "Rolling back $ENV to $PREV_VERSION"

# Plan the rollback
pfy nomad deploy --env $ENV --tag $PREV_VERSION --plan-only

read -p "Proceed with rollback? (yes/no) " CONFIRM
if [ "$CONFIRM" != "yes" ]; then
  echo "Rollback cancelled"
  exit 0
fi

# Execute rollback
pfy nomad deploy --env $ENV --tag $PREV_VERSION --yes

echo "✓ Rollback complete"

See Also ​