static-if
Compile-time conditionals that keep or drop jobs, steps, and keys before any YAML is emitted.
static-if is a compile-time conditional. Its expression is evaluated by the
transpiler, not by GitHub Actions. When it is false the guarded job, step, or map
is removed from the generated workflow entirely; when it is true the static-if
key is stripped and everything else is emitted verbatim.
Use static-if to shape the workflow at build time. Use the native if: for
runtime conditions that depend on github.*, needs.*, steps.*, and other
runtime contexts.
Form A — keep or drop a job or step
Place static-if directly on a job or step. A false expression deletes the whole
map from the output.
With params.deploy false, the release job never appears:
name: Deploy
on: [push]
params:
deploy:
type: boolean
default: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo build
release:
static-if: params.deploy
runs-on: ubuntu-latest
steps:
- run: ./release.shjobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo buildname: Deploy
on: [push]
params:
deploy:
type: boolean
default: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo build
release:
static-if: params.deploy
runs-on: ubuntu-latest
steps:
- run: ./release.shjobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo buildFlip default: true and the job is emitted with the static-if key removed.
Form B — conditional merge
static-if(<expr>): is a merge key. When the expression is true, its mapping is
merged into the parent map; when false, the whole block is dropped. This works on
jobs, steps, and env: maps.
name: Build
on: [push]
params:
debug:
type: boolean
default: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/upload-artifact@v4
with:
name: dist
static-if(params.debug):
retention-days: "1"jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/upload-artifact@v4
with:
name: dist
retention-days: "1"name: Build
on: [push]
params:
debug:
type: boolean
default: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/upload-artifact@v4
with:
name: dist
static-if(params.debug):
retention-days: "1"jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/upload-artifact@v4
with:
name: dist
retention-days: "1"static-if vs if
static-ifruns at compile time. False branches produce no YAML, so they cost nothing at runtime and never show up in the Actions UI.ifruns at runtime on GitHub's servers. The step or job is always present in the workflow; GitHub decides whether to run it.
They compose cleanly — a step can have both:
- name: Publish preview
static-if: params.deploy
if: github.ref == 'refs/heads/main'
run: ./publish-preview.shIf params.deploy is false the step is dropped at compile time. If it is true the
step is emitted with its if: intact for GitHub to evaluate at runtime.
Expression rules
- Operates only on compile-time roots:
params.*,for-each.*, anddefine.*. - Takes a bare expression —
${{ ... }}is runtime-only and rejected. - Must resolve to a boolean. Unknown references and non-boolean results are errors.
- Referencing a runtime context (
github,needs,steps, …) is an error; useif:for those.