Skip to main content
A step is the smallest unit of work in a pipeline. Every action step shares a common shape — id, optional name, timeout, and if condition — and adds fields specific to its type. Wrap steps in parallel or group blocks to control how they run. See Pipelines overview. Steps fall into three categories:
  • Module steps act on a module instance through its build or deploy manager: build, deploy, rollback.
  • CI steps run on provisioned compute that you configure with an infrastructure block: build:image, build:static, custom, terraform:plan, terraform:apply.
  • Control-flow steps shape the run itself: approval, sleep, trigger:pipeline.
Blocks are not steps: parallel and group have no id or type, and they hold steps rather than doing work. For every field, default, and nested type, see the pipeline configuration schema.

Module steps

build

Triggers a build for a module instance using the module’s own build configuration. Reference the module instance by unique ID (mi_…), environmentGivenId.moduleGivenId, or projectGivenId.environmentGivenId.moduleGivenId. Pass build parameters through input; outputs such as image_digest are available to later steps.
See BuildStep schema.

deploy

Triggers a deployment for a module instance using the module’s deploy configuration. Commonly consumes a preceding build’s output to pin the exact artifact. Concurrency is managed by the deploy manager lock, not the pipeline scheduler.
See DeployStep schema.

rollback

Reverts a module instance to a specific previous deployment by deployment_id. Use it in a rollback block to recover automatically when a pipeline fails.
See RollbackStep schema.

CI steps

CI steps run on compute you provision through an infrastructure block, which selects an execution environment or an AWS account, region, instance type, and size. See StepInfrastructure.
The nixpacks builder is deprecated for pipeline CI steps. Use railpack for automatic framework detection.

build:image

Builds a Docker image from a git source and pushes it to one or more ECR destinations. Build with a dockerfile or let railpack auto-detect the language and framework.
See BuildImageCiStep schema.

build:static

Builds static assets from a git source and uploads them to one or more S3 destinations. Build with a dockerfile or railpack.
See BuildStaticCiStep schema.

custom

Runs arbitrary shell commands on provisioned compute — tests, linters, migrations, or any scripted task. Optionally check out a git source, install tools with setup actions, and pass environment_variables.
See CustomCommandCiStep schema.

Publishing outputs

A custom step can publish string values for later steps to consume. Declare the output names in the step’s outputs list, then have your commands append name=value lines to the file at $RAVION_OUTPUT:
Later steps read the value with a template expression:
Only names declared in outputs are published — lines written to $RAVION_OUTPUT for undeclared names are ignored. Each name must be a valid shell variable name, and values are always strings.

terraform:plan

Generates a Terraform or OpenTofu plan and uploads the plan file to S3 for a later apply. Set plan_type to destroy to plan a teardown. Supply input variables with terraform_variables or terraform_variable_files.
See TerraformPlanCiStep schema.

terraform:apply

Applies a plan file produced by a preceding terraform:plan step. Reference the plan with plan_file_uri, typically from the plan step’s output.
See TerraformApplyCiStep schema.

Control-flow steps

approval

Pauses the pipeline until a user approves through the dashboard or REST API. Use it to gate production deployments behind a manual review.
See ApprovalStep schema.

sleep

Pauses execution for a fixed duration_ms. Useful for spacing out steps or for testing and debugging pipeline behavior.
See SleepStep schema.

trigger:pipeline

Starts another pipeline run and passes inputs to it. Optionally pin a pipeline_version_id or override behavior per variant with run.
See TriggerPipelineStep schema.

Blocks

Steps in a list run sequentially in order. Two block types change that: parallel runs its children at the same time, and group labels a nested sequence. Most pipelines need neither — a flat list of steps is the default shape, and many pipelines need only parallel.

parallel

Runs every child concurrently. The block finishes when all children finish, so a step after the block waits for all of them. Children are action steps or group blocks; a parallel block can’t directly contain another parallel block. fail_strategy controls what happens to the other children when one fails: finish-all (default) lets the block finish its remaining work, finish-running lets in-flight children finish their current step, and cancel-all cancels them immediately.
Use parallel when the children are independent of each other but something later in the pipeline depends on all of them. If nothing downstream depends on them together, they don’t belong in the same pipeline — see When not to use blocks. See ParallelStep schema.

group

Runs its steps sequentially, exactly as they would run at the top level, and shows them under one label in the UI. A group adds no scheduling behavior to its children; its optional concurrency config controls how competing executions of the whole group block are admitted across runs (by key and scope), not how the steps inside one run are throttled. Its main job is to put a multi-step sequence inside a parallel block, whose children are otherwise single steps:
Don’t wrap a top-level sequence in a group just to name it — a pipeline with one group containing all its steps is the same pipeline with extra nesting. Groups are the rarest block; if you aren’t nesting a sequence inside parallel or gating the block with a concurrency key, leave it out. See GroupStep schema.

When not to use blocks

A pipeline models one workflow: a set of steps that depend on each other through outputs, gates, or ordering. Blocks arrange the steps inside that workflow; they aren’t a way to run several unrelated workflows from one config. The pattern to avoid is a top-level parallel whose children are group blocks that each build and deploy a different service, with no step that depends on more than one of them:
Each group is a complete, self-contained build → deploy. Merging them buys nothing and costs independence: one failure fails the run, a trigger for one service runs the other, and re-running one means re-running both. Make each group its own pipeline with its own trigger:
api-pipeline.yaml
docs-pipeline.yaml
The test for keeping services in one pipeline: is there a step that needs both of them? A shared image build, a shared approval, an integration test that runs against both, or a required rollout order all qualify. “They belong to the same product” does not — that’s what a project is for. See One workflow per pipeline.