Secrets & Deployment
From continuous integration to continuous deployment — done safely.
Deploying means using credentials — API keys, cloud tokens, passwords. Hard-coding those in a workflow would leak them to anyone who can read the repo. GitHub Secrets store them safely, and environments add approval gates. Together they turn CI into full CD.
🎯 Learning Objectives
By the end of this lesson you will:
- Store and use secrets securely in workflows
- Understand repository vs environment secrets
- Add a deploy job that runs only after tests pass
- Protect production with environment approval rules
GitHub Secrets
Secrets are encrypted values you store in the repo settings (Settings → Secrets and variables → Actions). They’re never printed in logs and can’t be read back — only used.
Reference a secret with the secrets context:
steps:
- name: Deploy
run: ./deploy.sh
env:
API_TOKEN: ${{ secrets.API_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}⚠ Never echo a secret
Don’t echo a secret or write it to a file that gets uploaded. GitHub masks known secret values in logs, but careless handling (base64, string manipulation) can still expose them. Treat secrets as write-only.
Repository vs Environment Secrets
| Scope | Where it applies |
|---|---|
| Repository secret | Available to all workflows in the repo |
| Environment secret | Only available to jobs targeting that environment |
Environment secrets are more secure: your production database password lives only in the production environment, so a job that doesn’t target production can’t touch it.
A Deploy Job
Extend the pipeline: deploy only after CI passes, and only from main:
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test && npm run build
deploy:
needs: ci # wait for CI to pass
if: github.ref == 'refs/heads/main' # only from main
runs-on: ubuntu-latest
environment: production # use the production environment
steps:
- uses: actions/checkout@v4
- name: Deploy
run: ./deploy.sh
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}The three guardrails working together:
needs: ci— never deploy untested code.if: github.ref == 'refs/heads/main'— feature branches don’t deploy.environment: production— unlocks production secrets and any approval rules.
Environment Protection Rules
On the production environment you can require:
- Required reviewers — a human must click “Approve” before deploy runs.
- Wait timer — a delay before deployment proceeds.
- Branch restrictions — only specific branches may deploy.
💡 This is safe continuous deployment
With a required reviewer on production, your pipeline deploys automatically to staging but pauses for a human “go” before touching production. That’s the balance most teams want: fast, but with a safety catch on the highest-risk step.
🧪 Hands-on Lab
Add a Guarded Deploy Stage
- Store a fake
DEPLOY_TOKENas a repository secret - Add a
deployjob that needs the CI job and only runs onmain - Target a
productionenvironment and use the secret as an env var
🧠 Knowledge Check
How should credentials like an API token be handled in a GitHub Actions workflow?
Which combination ensures a deploy job only runs on tested code from the main branch?
💼 Interview Preparation
How do you design a safe deployment pipeline in GitHub Actions?
Summary
You’ve completed the GitHub Actions track: CI/CD concepts, workflow anatomy, a full CI pipeline, and now secure secrets and gated deployment. You can automate the whole path from push to production safely. Next, we explore another major CI/CD tool used across the industry: Jenkins.