GitHub Actions Tutorial — Environments
Environments
Environments are named deployment targets — like staging, production, or preview. They let you attach protection rules, environment-specific secrets, and deployment tracking to your workflows.
Creating Environments
Go to: Settings → Environments → New environment
Common environments:
| Environment | Purpose |
|---|---|
development |
Dev/feature testing |
staging |
Pre-production validation |
production |
Live deployment |
Using Environments in Workflows
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- run: echo "Deploying to staging..."
env:
API_URL: ${{ vars.API_URL }} # env-specific variable
API_KEY: ${{ secrets.API_KEY }} # env-specific secret
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- run: echo "Deploying to production..."
env:
API_URL: ${{ vars.API_URL }} # different value than staging
API_KEY: ${{ secrets.API_KEY }} # different secret than staging
Protection Rules
| Rule | Purpose |
|---|---|
| Required reviewers | Someone must approve before deployment |
| Wait timer | Delay deployment by N minutes |
| Branch restrictions | Only specific branches can deploy |
| Custom rules | Use deployment protection rules API |
Required Reviewers
When a workflow reaches a job with environment: production and required reviewers are set, it pauses and waits for approval:
Job reaches environment: production
↓
⏸ Waiting for approval
↓
Reviewer approves in Actions UI
↓
Job continues
Environment-Specific Secrets and Variables
Each environment can have its own secrets and variables:
| Variable | staging | production |
|---|---|---|
API_URL |
https://api-staging.example.com |
https://api.example.com |
API_KEY |
stg_key_xxx |
prod_key_yyy |
DB_HOST |
db-staging.internal |
db-prod.internal |
The same ${{ secrets.API_KEY }} reference resolves to different values based on the environment.
Environment with URL
Display the deployment URL in the Actions UI:
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://myapp.example.com
steps:
- run: echo "Deployed!"
Deployment Pipeline Pattern
name: Deploy Pipeline
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
deploy-staging:
needs: test
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.myapp.com
steps:
- uses: actions/checkout@v4
- run: echo "Deploying to staging..."
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://myapp.com
steps:
- uses: actions/checkout@v4
- run: echo "Deploying to production..."
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
┌──────┐ ┌─────────────┐ ┌──────────────────┐
│ test │ → │ staging │ → │ production │
│ │ │ (auto) │ │ (requires review)│
└──────┘ └─────────────┘ └──────────────────┘
Common Mistakes
| Mistake | Fix |
|---|---|
| Environment secrets not available | Ensure environment: is set on the job |
| Approval not required | Configure required reviewers in Settings → Environments |
| Wrong secret value | Check you’re using the correct environment name |
| Can’t deploy from feature branch | Check branch restrictions on the environment |
Quick Reference
| Feature | Syntax |
|---|---|
| Use environment | environment: production |
| With URL | environment: name: prod, url: https://... |
| Env secret | ${{ secrets.NAME }} (resolved per environment) |
| Env variable | ${{ vars.NAME }} (resolved per environment) |
| Protection | Required reviewers, wait timer, branch rules |
← Previous: GITHUB_TOKEN
Next: OIDC Tokens →