Skip to content
FlightStack Docs
Sign in Start free

Variables, Secrets & Step Outputs | FlightStack

FlightStack pipelines have three sources of dynamic data:

  • Variables — configuration values (org / repo / pipeline scoped).
  • Secrets — variables flagged isSecret: true, encrypted at rest, masked in logs.
  • Step outputs — values emitted by upstream jobs and consumed downstream.

All three are read with the same ${{ ... }} syntax.

ExpressionResolves to
${{ vars.API_BASE_URL }}Variable named API_BASE_URL from the resolved scope.
${{ secrets.SENTRY_DSN }}Secret. Available only on the agent at execution time.
${{ steps.<jobId>.outputs.<name> }}Output <name> from a previously executed job.
${{ context.branch }}Run context (branch, commit, eventType, …).

Expressions can appear in:

  • Job inputs (e.g. an Android keystore alias from a secret)
  • Shell-job command strings
  • Notification message bodies and webhook URLs
  • Connection condition fields (see Connections)
ScopeDefined onInheritance
OrganizationAn organizationAll repos and pipelines in that org
RepositoryA connected repoAll pipelines on that repo
Variable groupA named bagAny pipeline that attaches the group
PipelineA single pipelineOnly that pipeline’s runs
Per-runPOST /build bodyOne specific build only

When a pipeline runs, FlightStack composes variables in this order (later overrides earlier):

  1. Organization-scoped variables
  2. Variable groups attached to the pipeline
  3. Repository-scoped variables
  4. Pipeline-scoped variables
  5. Per-run overrides

The same rule applies to secrets.

Each job can emit named outputs. Downstream jobs reference them with ${{ steps.<jobId>.outputs.<name> }}.

In your step’s spec (marketplace step or custom step):

outputs:
- name: deployedUrl
description: Public URL after deploy
- name: changedCount
description: Number of screenshots that changed

Inside a shell job (or any custom step), use the fs-output helper:

Terminal window
fs-output deployedUrl "https://acme.web.app"
fs-output changedCount 3

fs-output is on the agent’s PATH automatically. It writes to the run’s output sink and sends them back to the server via POST /Pipeline/job-runs/{jobRunId}/outputs.

Reference by <jobId> — the ID you assigned the upstream job in the pipeline definition, not the human-readable name:

# Notify job
inputs:
message: |
Deploy finished: ${{ steps.deploy.outputs.deployedUrl }}
ScreenStack diffs: ${{ steps.screen.outputs.changedCount }}

Every job is invoked with its declared inputs exposed as FS_IN_* environment variables on the agent. So an input named flutterVersion becomes FS_IN_FLUTTER_VERSION. Useful for shell jobs that consume configured inputs without doing their own templating:

Terminal window
echo "Building with Flutter $FS_IN_FLUTTER_VERSION"
flutter pub get

This mirrors the well-known INPUT_* convention from GitHub Actions, with our FS_IN_ prefix.

ExpressionValue
context.repositoryFull repo name (e.g. acme/mobile).
context.branchBranch being built.
context.commitFull commit SHA.
context.commitShortShort SHA (7 chars).
context.commitMessageFirst line of the commit message.
context.authorCommit author name.
context.eventTypepush, tag, pullRequest, manual, schedule.
context.runNumberPipeline run number.
context.runIdUUID of the run.
context.timestampISO-8601 run start time.

Secrets are decrypted only on the agent, at the moment of execution, and shredded when the job ends.

For code-signing material (keystores, provisioning profiles, App Store Connect keys, Play service accounts, Firebase configs), use the dedicated code-signing vault rather than secrets — it’s better suited to binary blobs and adds expiration tracking.

  1. Navigate to SettingsVariables at the org, repo, or pipeline level.
  2. Add Variable or Add Secret, set the key/value, save.

See Secrets API.

  1. Use secrets for anything sensitive. Plain variables are visible in the dashboard.
  2. Name in uppercase with underscores — PROD_API_KEY, not prodKey.
  3. Scope appropriately. Don’t lift repo-specific values to the org.
  4. Prefer step outputs over re-deriving — once a job emits version, downstream jobs should consume it instead of recomputing.
  5. Rotate periodically. Audit who has access on a cadence.