Skip to content

๐Ÿงช GitHub Actions and Environment Variables: Static vs. Dynamic Smackdown

Letโ€™s talk about environment variables in GitHub Actions โ€” those little gremlins that either make your CI/CD run silky smooth or throw a wrench in your perfectly crafted YAML.

If you’ve ever squinted at your pipeline and wondered, โ€œWhere the heck should I declare this ANSIBLE_CONFIG thing so it doesnโ€™t vanish into the void between steps?โ€, youโ€™re not alone. Iโ€™ve been there. Iโ€™ve screamed at $GITHUB_ENV. Iโ€™ve misused export. Iโ€™ve over-engineered echo. But fear not, dear reader โ€” Iโ€™ve distilled it down so you donโ€™t have to.

In this post, weโ€™ll look at the right ways (and a few less right ways) to set environment variables โ€” and more importantly, when to use static vs dynamic approaches.


๐ŸงŠ Static Variables: Set It and Forget It

Got a variable like ANSIBLE_STDOUT_CALLBACK=yaml thatโ€™s the same every time? Congratulations, youโ€™ve got yourself a static variable! These are the boring, predictable, low-maintenance types that make your CI life a dream.

โœ… Best Practice: Job-Level env

If your variable is static and used across multiple steps, this is the cleanest, classiest, and least shouty way to do it:

jobs:
  my-job:
    runs-on: ubuntu-latest
    env:
      ANSIBLE_CONFIG: ansible.cfg
      ANSIBLE_STDOUT_CALLBACK: yaml
    steps:
      - name: Use env vars
        run: echo "ANSIBLE_CONFIG is $ANSIBLE_CONFIG"

Why it rocks:

  • ๐Ÿ‘€ Super readable
  • ๐Ÿ“ฆ Available in every step of the job
  • ๐Ÿงผ Keeps your YAML clean โ€” no extra echo commands, no nonsense

Unless you have a very specific reason not to, this should be your default.


๐ŸŽฉ Dynamic Variables: Born to Be Wild

Now what if your variables arenโ€™t so chill? Maybe you calculate something in one step and need to pass it to another โ€” a file path, a version number, an API token from a secret backend ritual…

Thatโ€™s when you reach for the slightly moreโ€ฆ creative option:

๐Ÿ”ง $GITHUB_ENV to the rescue

- name: Set dynamic environment vars
  run: |
    echo "BUILD_DATE=$(date +%F)" >> $GITHUB_ENV
    echo "RELEASE_TAG=v1.$(date +%s)" >> $GITHUB_ENV

- name: Use them later
  run: echo "Tag: $RELEASE_TAG built on $BUILD_DATE"

What it does:

  • Persists the variables across steps
  • Works well when values are calculated during the run
  • Makes you feel powerful

๐Ÿช„ Fancy Bonus: Heredoc Style

If you like your YAML with a side of Bash wizardry:

- name: Set vars with heredoc
  run: |
    cat <<EOF >> $GITHUB_ENV
    FOO=bar
    BAZ=qux
    EOF

Because sometimes, you just want to feel fancy.


๐Ÿ˜ตโ€๐Ÿ’ซ What Not to Do (Unless You Really Mean It)

- name: Set env with export
  run: |
    export FOO=bar
    echo "FOO is $FOO"

This only works within that step. The minute your pipeline moves on, FOO is gone. Poof. Into the void. If thatโ€™s what you want, fine. If not, donโ€™t say I didnโ€™t warn you.


๐Ÿง  TL;DR โ€“ The Cheat Sheet

ScenarioBest Method
Static variable used in all stepsenv at the job level โœ…
Static variable used in one stepenv at the step level
Dynamic value needed across steps$GITHUB_ENV โœ…
Dynamic value only needed in one stepexport (but donโ€™t overdo it)
Need to show off with Bash skillscat <<EOF >> $GITHUB_ENV ๐Ÿ˜Ž

๐Ÿงช My Use Case: Ansible FTW

In my setup, I wanted to use:

ANSIBLE_CONFIG=ansible.cfg
ANSIBLE_STDOUT_CALLBACK=yaml

These are rock-solid, boringly consistent values. So instead of writing this in every step:

- name: Set env
  run: |
    echo "ANSIBLE_CONFIG=ansible.cfg" >> $GITHUB_ENV

I now do this:

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      ANSIBLE_CONFIG: ansible.cfg
      ANSIBLE_STDOUT_CALLBACK: yaml
    steps:
      ...

Cleaner. Simpler. One less thing to trip over when Iโ€™m debugging at 2am.


๐Ÿ’ฌ Final Thoughts

Environment variables in GitHub Actions arenโ€™t hard โ€” once you know the rules of the game. Use env for the boring stuff. Use $GITHUB_ENV when you need a little dynamism. And remember: if youโ€™re writing export in step after step, something probably smells.

Got questions? Did I miss a clever trick? Want to tell me my heredoc formatting is ugly? Hit me up in the comments or toot at me on Mastodon.


โœ๏ธ Posted by Amedee, who loves YAML almost as much as dancing polskas.
๐Ÿ’ฅ Because good CI is like a good dance: smooth, elegant, and nobody falls flat on their face.
๐ŸŽป Scheduled to go live on 20 August โ€” just as Boombalfestival kicks off. Because why not celebrate great workflows and great dances at the same time?

Leave a Reply