Deploy Pipeline
The deploy pipeline is Norn's core orchestration flow. It takes an app from source code to running Nomad allocations in 9 sequential steps. For a deploy rehearsal that stops before runtime mutation, use norn preflight.
Pipeline Steps
1. Clone
Checks out the git repository at the specified ref (commit SHA, branch, or tag). Uses NORN_GIT_TOKEN or NORN_GIT_SSH_KEY for private repos.
2. Build
Builds a Docker image using the Dockerfile specified in the infraspec (defaults to Dockerfile). Tags the image with the commit SHA and pushes to the configured registry (NORN_REGISTRY_URL).
3. Test
Runs the test command from build.test if defined. A non-zero exit code fails the pipeline. Skipped if no test command is configured.
4. Snapshot
Creates a PostgreSQL database snapshot (pg_dump) if the app declares infrastructure.postgres. The snapshot is stored and can be restored later via norn snapshots <app> restore <ts>.
5. Migrate
Runs database migrations from the migrations directory if specified. Migrations are applied to the database declared in infrastructure.postgres.database.
6. Submit
The core translation step:
- Resolves secrets from SOPS-encrypted
secrets.enc.yaml - Provisions declared
infrastructure.objectStoragebuckets and app-scoped S3 env - Calls
nomad.Translate()to convert the infraspec into a Nomad service job - For each process with a
schedule, callsnomad.TranslatePeriodic()to create separate periodic batch jobs - Submits all jobs to Nomad via the API
7. Healthy
Polls Nomad for allocation health. Waits for all task groups to have at least one healthy allocation. Broadcasts deploy.progress WebSocket events during polling.
The Nomad update strategy (set by the translator) handles rolling updates:
MaxParallel: 1— one allocation at a timeMinHealthyTime: 30s— must be healthy for 30 secondsAutoRevert: true— auto-rollback on health failure
8. Forge
Updates cloudflared tunnel ingress rules if the app defines endpoints. Maps each endpoint URL to the app's Consul service address.
9. Cleanup
Removes temporary build artifacts (cloned repo, build context).
Preflight Pipeline
norn preflight <app> [ref] runs the front half of the deploy path without creating a deployment record or touching Nomad, Postgres snapshots, migrations, or cloudflared routing.
| Step | What it checks |
|---|---|
validate | Runs infraspec validation using the configured Norn network mode |
clone | Prepares the same source tree deploy would use, including repo auth and local fallback behavior |
inspect | Verifies infraspec.yaml, the configured Dockerfile, declared encrypted secrets, and known source footguns |
build | Runs a local Docker build with the same build args as deploy, but does not push to the registry |
test | Runs build.test from the prepared source tree |
Preflight warnings are emitted as saga progress events. They do not fail the run unless they reveal a hard deploy blocker. Current warnings include disabled repo.autoDeploy and Go module replace directives pointing at parent directories, because those can make host-side tests differ from the Docker build context.
The Docker image/layer cache may remain locally after preflight. Norn runtime state does not change.
Sequence Diagram
Real-Time Progress
The pipeline broadcasts WebSocket events at each step transition:
| Event Type | Payload | When |
|---|---|---|
deploy.step | {step, sagaId, status} | Step starts, completes, or fails |
deploy.failed | {sagaId, error} | Pipeline fails |
deploy.completed | {sagaId, imageTag} | Pipeline succeeds |
preflight.step | {step, sagaId, status} | Preflight step starts, completes, or fails |
preflight.progress | {sagaId, message} | Preflight warning or informational check |
preflight.failed | {sagaId, error} | Preflight fails |
preflight.completed | {sagaId, imageTag} | Preflight succeeds |
The CLI connects to the WebSocket during norn deploy and norn preflight and renders a live progress display. The UI dashboard updates the deploy panel in real time.
Saga Event Log
Every step transition is recorded as an immutable saga event. See Saga Events for the full event model.
Provenance
Deployments record source provenance in the deployment row as well as saga events. norn status, norn ops platform, and deployment history can show:
sourceKind:git_clone,local_copy,local_fallback, orrollbacksourceRef: the requested git ref, local fallback ref, or rollback source deploymentsourceDirty: whether the local source tree had uncommitted changessourceChanges: a value-safe list of changed file paths
Dirty local builds also receive an image tag suffix ending in -dirty, making runtime state visibly different from a clean commit build.