Skip to content

Nomad Deployment Commands ​

pfy nomad turns the deployment spec stored in the Manager into a Nomad job file and runs it: render writes the job, deploy renders, validates, plans, and runs it, and adopt imports an existing hand-written job into the spec. update-image, validate, and plan are helpers for hand-written HCL files. All of them shell out to the nomad CLI, which must be on your PATH.

Jobs are rendered from a deployment spec

pfy nomad render renders a full Nomad job from the deployment spec on the Manager's Deployment entity, and pfy nomad deploy runs render → nomad job validate → nomad job plan → nomad job run. The in-place image/tag rewrite is deprecated and only runs behind --legacy-rewrite. See Generated Artifacts and deployment.

Overview ​

The pfy nomad command group provides:

  • render - Render a full Nomad job from the deployment spec (deterministic, GENERATED header, spec hash stamped)
  • adopt - Adopt a hand-written job file into the deployment spec (the migration path)
  • deploy - Render, validate, plan, and run the job, or the application's whole stack with --stack
  • update-image / validate / plan - Legacy utilities for hand-written HCL files

Targeting flags ​

Every spec-consuming command (render, adopt, deploy, and the deployment commands) shares the same target flags to point at one (application, environment) Deployment:

FlagShortDescription
--env-eEnvironment alias from project.yaml (resolves to an application + deployment)
--appApplication ID (overrides project.yaml; needed when the env alias has no application_id)
--deployment-idTarget a specific deployment by ID (skips env→deployment resolution)
--nameNomad job/service name (defaults to the deployment's server-derived upstream)
--tenantTenant slug: target that tenant's dedicated deployment (default: the shared deployment)
--serviceService slug within the application (default: the application's primary service)

Commands ​

pfy nomad render ​

Render a full Nomad job from the deployment spec.

Usage:

bash
pfy nomad render --env <alias> [--tag <tag>] [--out <file>]

Flags (in addition to the targeting flags):

  • -t, --tag - Image tag for this release (appended to the spec's image)
  • --use-project-version, --pv - Use the version from project.yaml as the image tag
  • --region - Nomad region (default: global)
  • --optimizer-endpoint - Autoscaler optimizer endpoint for the productify-scaler strategy
  • --out - Output file (defaults to project.yaml ci.nomad_file; -, or unset with no nomad_file, prints to stdout). There is no -o short form; a -o before the subcommand is the global output-format flag

Examples:

bash
# Render prod's job to the committed artifact path from project.yaml
pfy nomad render --env prod --tag v1.2.3

# Render a dedicated tenant's job to stdout
pfy nomad render --env prod --tenant acme --tag v1.2.3 --out -
Rendered myapp job to nomad/myapp.nomad.hcl (spec 3f9a2c…)

The rendered file carries a GENERATED header with the spec hash and never contains secrets (secrets flow through Nomad template stanzas at runtime).

When the spec has scaling enabled, the rendered scaling block carries a productify-scaler strategy with metric_app_name (the application UUID, which is the app label the proxy stamps on the pfy_* metrics the optimizer forecasts from), group and task (both the job name, which are the labels on the Nomad allocation metrics), min/max, and optimizer_url (--optimizer-endpoint, default http://productify-optimizer.service.consul:8015). The application UUID is read from the Manager's Deployment.applicationId; rendering with scaling enabled fails if it cannot be resolved rather than falling back to the job name, which matches no series.

pfy nomad adopt ​

Adopt a hand-written Nomad job file into the deployment spec, the migration path off hand-maintained HCL. It reads the job file, extracts everything that maps onto the spec, writes that spec to the Manager (same GraphQL path as pfy deployment set), renders the generated job from it, and prints the residual: every stanza that did not map, with guidance to triage each into extra_hcl or a template feature request. Nothing is silently dropped.

Usage:

bash
pfy nomad adopt <jobfile.hcl> --env <alias> [--dry-run] [-o json|yaml]

Flags (in addition to the targeting and render flags above):

  • --dry-run - Preview the extracted spec, render, and residual without writing to the Manager
  • -o, --output - Machine-readable report format: json or yaml (default: human-readable text; note this local -o is the report format, not a file)

Example:

bash
pfy nomad adopt nomad/myapp.nomad.hcl --env prod --dry-run
Adopted nomad/myapp.nomad.hcl → application job "myapp"

Mapped onto the deployment spec:
  image: ghcr.io/acme/myapp
  count: 2
  …
  note: image tag "v1.2.3" is not part of the spec — supply it at deploy time with --tag (or --use-project-version)

Residual — 1 stanza did NOT map; triage each into the spec's extra_hcl or request a spec field:
  …

[DRY RUN] spec NOT written. Re-run without --dry-run to write it to deployment <id>.

Notes:

  • The image tag and the region are render-time inputs, not spec fields; the adopted values are reported and reused for the render preview.
  • The machine-readable report (-o json) contains job_name, spec, image_tag, region, residual[] (path/reason/guidance/snippet), written, and spec_hash, all stable snake_case keys for CI.
  • Run with --dry-run first: a real run writes the spec before rendering the preview.

pfy nomad deploy ​

Render the Nomad job from the deployment spec, then validate, plan, and run it.

Usage:

bash
pfy nomad deploy --env <alias> [--tag <tag>] [flags]

Flags (in addition to the targeting/render flags and --project/--project-id for --stack slug resolution):

  • --out - Write the rendered job here before deploying (defaults to project.yaml ci.nomad_file). No -o short form
  • --yes - Skip the nomad job plan confirmation step and run immediately
  • --plan-only - Render + validate + plan, but do not run
  • --skip-validation - Skip the nomad job validate step
  • --dry-run - Render and print without writing, validating, or deploying
  • --stack - Apply the application's whole stack for this environment in dependency order (see below)
  • --legacy-rewrite - Deprecated: run the in-place image= rewriter instead of rendering from the spec
  • -f, --file - --legacy-rewrite only: path to the hand-written HCL file to rewrite
  • -i, --image - --legacy-rewrite only: image name to rewrite into the file

Examples:

bash
# Deploy prod with an explicit tag
pfy nomad deploy --env prod --tag v1.2.3 --yes

# Deploy using the version from project.yaml
pfy nomad deploy --env prod --use-project-version --yes

# Plan only — review before deploying
pfy nomad deploy --env prod --tag v1.2.3 --plan-only

# Preview the rendered job without touching anything
pfy nomad deploy --env prod --tag v1.2.3 --dry-run

Workflow:

  1. Resolves the target deployment and renders the full job from its spec
  2. Writes it to --out / ci.nomad_file (the committed artifact)
  3. Validates the job file (unless --skip-validation)
  4. Runs nomad job plan as a review step (skipped with --yes; --plan-only stops here and prints the pfy nomad deploy --env <alias> --yes command to run next)
  5. Runs nomad job run
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 compares the spec hash stamped on the running job with the new one (Re-deploying spec … when they match; a bare Deploying spec … when the job is not running yet).

Stack deploys (--stack) ​

--stack applies the whole application stack for one (application, environment[, tenant]) in dependency order: managed data stores first (seeding any missing store credential on the way), then their backup jobs, then the services that consume them, waiting for each stage to become healthy before starting the next.

Stack-only flags:

  • --out-dir - Directory the rendered stack jobs are written to (default: deploy/)
  • --only-data - Apply just the managed data stores and their backup jobs
  • --no-wait - Do not gate stages on health (faster when stores are already up; a service can start before its database accepts connections)
  • --wait-timeout - How long each stage has to become healthy (default: 5m)
  • --install - Path to install.yaml, which defines the named backup_targets a store's backup policy resolves against (default: install.yaml)
  • --service <slug> - Narrow the apply to one service's job (--only-data together with --service selects nothing and is refused)
bash
# Apply the full stack for prod: postgres first, then the services
pfy nomad deploy --stack --env prod --app myapp --project my-saas --tag v1.2.3 --yes

# Only the data stores
pfy nomad deploy --stack --env prod --app myapp --project my-saas --only-data --yes

Under --stack, --app accepts a slug (resolved via --project) or an ID. Each stage prints what it rendered and ran:

Generated a credential for main at <nomad variable 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)

Legacy rewrite (--legacy-rewrite) ​

The in-place image= rewriter is deprecated and runs only behind --legacy-rewrite. Every use prints a WARNING: --legacy-rewrite is DEPRECATED ... line on stderr:

bash
pfy nomad deploy --legacy-rewrite -f manager/nomad/manager.nomad --tag v1.2.3

Without --legacy-rewrite, pfy nomad deploy -f <file> --tag <tag> goes through the spec-render flow and ignores -f. Use pfy nomad render/deploy, or pfy nomad adopt to import the hand-written file into the spec once and render from then on.


pfy nomad update-image ​

Update only the image/tag in a hand-written Nomad HCL file without deploying (legacy image= rewriter).

Usage:

bash
pfy nomad update-image -f <file> [options]

Flags:

  • -f, --file (required) - Path to the Nomad HCL file
  • -i, --image - Docker image name
  • -t, --tag - Docker image tag/version
  • --use-project-version, --pv - Use version from project.yaml as the image tag

Examples:

Update only the tag:

bash
pfy nomad update-image -f manager/nomad/manager.nomad --tag v1.2.3

Update using project version:

bash
pfy nomad update-image -f manager/nomad/manager.nomad --use-project-version

Interpolated image references are skipped

An image line built from a variable, such as image = "${IMAGE_NAME}:${TAG}", cannot be rewritten without destroying the interpolation, so update-image (and the legacy deploy --legacy-rewrite) leave it byte-for-byte untouched and report it:

Skipped job.nomad:5: image = "${IMAGE_NAME}:${TAG}" interpolates a variable; left unchanged
  rewriting it would destroy the interpolation; set the tag through the job's variable instead (nomad job run -var ...) or use a job file with a literal image

Set the tag through the job's own variable (nomad job run -var ...) instead, or use a job file with a literal image reference. Other image lines in the same file are still updated normally, and --dry-run (on deploy --legacy-rewrite) reports the same skip as [DRY RUN] Would skip ....

Registry ports are preserved: the tag is split on the last colon only when it follows the last slash, so localhost:5000/acme/app:1.0.0 updates to localhost:5000/acme/app:2.0.0.


pfy nomad validate ​

Validate a Nomad HCL job file.

Usage:

bash
pfy nomad validate -f <file>

Flags:

  • -f, --file (required) - Path to the Nomad HCL file

Example:

bash
pfy nomad validate -f manager/nomad/manager.nomad

This runs nomad job validate to check the job file syntax and configuration.


pfy nomad plan ​

Run nomad job plan on a HCL file to preview changes.

Usage:

bash
pfy nomad plan -f <file>

Flags:

  • -f, --file (required) - Path to the Nomad HCL file

Example:

bash
pfy nomad plan -f manager/nomad/manager.nomad

This shows what changes would be made to the Nomad cluster without actually applying them.


Integration with Version Management ​

The Nomad commands take the image tag from the project version:

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

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

The project version and the deployed container tag then stay in step.


Common Workflows ​

Simple Deployment ​

bash
# Update version
pfy version set --version 1.2.3

# Deploy to Nomad from the spec
pfy nomad deploy --env prod --use-project-version --yes

Safe Deployment with Planning ​

bash
# Render, validate, and plan; review before deploying
pfy nomad deploy --env prod --tag v1.2.3 --plan-only

# Review the plan output, then deploy
pfy nomad deploy --env prod --tag v1.2.3 --yes

Multi-Environment Deployment ​

With one project.yaml env alias per environment (seeded by pfy sync, managed by pfy env):

bash
# Development
pfy nomad deploy --env dev --tag dev-latest --yes

# Staging
pfy nomad deploy --env staging --tag v1.2.3 --yes

# Production: plan first
pfy nomad deploy --env prod --tag v1.2.3 --plan-only
# Review plan, then:
pfy nomad deploy --env prod --tag v1.2.3 --yes

Migrating a hand-written job file ​

bash
# 1. Preview what maps and what doesn't
pfy nomad adopt nomad/myapp.nomad.hcl --env prod --dry-run

# 2. Write the spec to the Manager
pfy nomad adopt nomad/myapp.nomad.hcl --env prod

# 3. From now on, render and deploy from the spec
pfy nomad deploy --env prod --tag v1.2.3 --yes

Prerequisites ​

  • The nomad CLI on your PATH (render alone does not need it; validate, plan, deploy, adopt's preview, and deploy diff's cluster check do)
  • NOMAD_ADDR (and NOMAD_TOKEN if ACLs are on) pointing at the cluster
  • A Nomad token allowed to plan and run jobs in the target namespace
  • Manager credentials (pfy login); the spec is read from the Manager

See Also ​