An environment is a named deployment target with its own secrets, variables and protection rules, created on first use or with gh 29 api -X PUT repos/{owner}/{repo}/environments/staging. BookNest's deployment workflow (pull requests #19 and #20) runs one job per environment:
name: Deploy
on: workflow_dispatch
permissions:
contents: read
jobs:
staging:
runs-on: ubuntu-24.04
environment: staging
steps:
- name: Use a secret and a variable
env:
SHELF_API_KEY: ${{ secrets.SHELF_API_KEY }}
run: |
echo "Region ${{ vars.CATALOG_REGION }}, key $SHELF_API_KEY"
echo "Key length ${#SHELF_API_KEY}"
echo "Reversed, first 6: $(rev <<< "$SHELF_API_KEY" | cut -c1-6)"
echo "Base64: $(printf %s "$SHELF_API_KEY" | base64)"
production:
needs: staging
runs-on: ubuntu-24.04
environment:
name: production
url: https://booknest.example.com
steps:
- env:
SHELF_API_KEY: ${{ secrets.SHELF_API_KEY }}
run: echo "Deploy ${GITHUB_SHA::7} to ${{ vars.CATALOG_REGION }}, key $SHELF_API_KEY"staging has no values of its own, so it gets the repository's secret and ap-southeast-1; production gets its own secret and eu-west-1. The url appears on the run page and in the repository's Deployments list, where each job that names an environment leaves a deployment record. The echo lines exist to show what logs reveal (Secret Hygiene); a real step would hand the secret to a CLI instead.