# static-if (/docs/macros/static-if)



`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 [#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:

<CodeCompare>
  ```yaml title=".actio.yml"
  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.sh
  ```

  ```yaml title="generated .yml"
  jobs:
    build:
      runs-on: ubuntu-latest
      steps:
        - run: echo build
  ```
</CodeCompare>

Flip `default: true` and the job is emitted with the `static-if` key removed.

## Form B — conditional merge [#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.

<CodeCompare>
  ```yaml title=".actio.yml"
  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"
  ```

  ```yaml title="generated .yml"
  jobs:
    build:
      runs-on: ubuntu-latest
      steps:
        - uses: actions/upload-artifact@v4
          with:
            name: dist
            retention-days: "1"
  ```
</CodeCompare>

## `static-if` vs `if` [#static-if-vs-if]

* `static-if` runs at **compile time**. False branches produce no YAML, so they
  cost nothing at runtime and never show up in the Actions UI.
* `if` runs 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:

```yaml title=".actio.yml"
- name: Publish preview
  static-if: params.deploy
  if: github.ref == 'refs/heads/main'
  run: ./publish-preview.sh
```

If `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 [#expression-rules]

* Operates only on compile-time roots: `params.*`, `for-each.*`, and `define.*`.
* 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; use
  `if:` for those.


## Sitemap

Browse the full documentation: [Markdown sitemap](https://austenstone.github.io/actio/sitemap.md) · [XML sitemap](https://austenstone.github.io/actio/sitemap.xml)