Stages and jobs
A pipeline compiles to a flat DAG of jobs. Stages are grouping plus default edges. Cycles are errors.
stages: - name: build jobs: - name: compile runs_on: [linux, x64, docker] container: image: golang:1.27 env: { CGO_ENABLED: "0" } user: "1000" env: { FOO: bar } steps: - uses: slipway/checkout@v1 - run: go build ./... - name: test needs: [build] # all jobs of this stage wait for the build stage jobs: [...] - name: deploy-staging needs: [test] jobs: - name: deploy environment: staging steps: - uses: slipway/deploy@v1 with: { service: api, release: "${{ needs.build.outputs.version }}", strategy: rolling }- Stage names are unique. Job names are unique across the pipeline, so
needscan reference them directly. needsmay reference jobs or stages. Omitted on a stage, it means “the previous stage”. Omitted on a job, it means “nothing in this stage”: jobs in a stage run in parallel unless theyneedeach other.needs: []on a stage removes the implicit previous-stage edge.ifon a job evaluates afterneedsresolve. The functionssuccess(),failure(),always()andcancelled()refer to the needed jobs. The default issuccess().- Limits: at most 500 jobs after matrix expansion per run (configurable per plan), 100 steps per job, 20 services per job.
Job options
Section titled “Job options”| Key | Purpose |
|---|---|
runs_on |
Runner labels the job must match; default from defaults.runs_on |
container |
Run steps inside this image (docker and kubernetes executors) |
services |
Sidecar containers with health checks: services |
env |
Job-level environment |
needs |
Dependencies |
if |
Condition (CEL, braces optional) |
timeout |
Duration like 20m, 2h. Maximum is plan-limited: Free 60m, Team 6h, Business 24h |
retry |
{ max, backoff, when }, where when is any of runner_lost, timeout, failure, any |
allow_failure |
A failure does not fail the run |
matrix |
Build matrix |
concurrency |
{ group, cancel_in_progress } at job level |
cache, artifacts |
Caches and artifacts |
outputs |
Exported as needs.<job>.outputs.<key> |
environment |
Binds the job to a deploy environment |
See the generated job reference for every field with types.
Matrix
Section titled “Matrix”- name: compile matrix: os: [linux, windows] go: ["1.26", "1.27"] include: [{ os: linux, go: "1.27", coverage: true }] exclude: [{ os: windows, go: "1.26" }] fail_fast: true max_parallel: 4 runs_on: [${{ matrix.os }}] steps: - run: go test ./...Expansion happens at compile time. matrix.<key> is available in expressions, and the job’s display name becomes compile (linux, 1.27). fail_fast cancels the remaining combinations on the first failure; max_parallel caps concurrency.
Retries and timeouts
Section titled “Retries and timeouts”retry: { max: 2, backoff: 30s, when: [runner_lost, timeout] }timeout: 20mRetries re-queue the job as a new attempt. Use runner_lost to survive spot-instance interruptions without masking real failures.
Deploy jobs
Section titled “Deploy jobs”A job with environment: is a deploy job:
environment: name: production url: https://api.example.com # shown in the UI service: api # the Service being deployedEffects:
- The job waits for the environment’s protection rules (approvals, windows, freezes, policies) before it starts. While it waits its status is
waiting_approval. environment.vars.*and environment-scoped secrets are injected.- The run is recorded as a deployment of the given release, and your SCM receives a deployment status.
slipway/deploy@v1delegates to the deploy engine’s strategy (rolling, blue/green, canary with verification). The pipeline shows progress but does not implement the strategy.
You can also skip deploy jobs entirely: create a release with slipway/release-create@v1 and let lifecycles drive promotion. Both models are supported. The deploy domain is the source of truth for what is where.