Secrets, Variables and Environments in GitHub Actions
Workflows need configuration (URLs, flags) and credentials (API keys, deploy tokens). GitHub provides separate tools for each, plus environments to control who and what can deploy where.
Secrets and variables
- Secrets are encrypted, masked in logs and not readable after saving. Use them for credentials.
- Variables are plain-text configuration. Use them for non-sensitive values like region names or feature flags.
- Both can be defined at organisation, repository or environment level.
steps:
- run: ./scripts/notify.sh
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
APP_REGION: ${{ vars.APP_REGION }}
Pass secrets as environment variables, not inline in commands, so they don't end up in shell history or process listings.
Environments
jobs:
deploy-production:
runs-on: ubuntu-latest
environment:
name: production
url: https://shop.example.com
steps:
- run: ./deploy.sh
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }} # the production environment's secret
In the repository settings, an environment can have:
- Its own secrets and variables, available only to jobs that target it.
- Required reviewers who must approve before the job runs.
- A wait timer before deployment.
- Deployment branch rules, for example only
maincan deploy to production.
Safety rules
- Secrets aren't passed to workflows triggered by pull requests from forks.
- Never
echoa secret; masking catches exact values but not transformed ones (base64, substrings). - Prefer short-lived credentials via OIDC over long-lived cloud keys stored as secrets.
- Rotate secrets regularly and immediately when someone leaves the team.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.