GitHub Actions deployment
Add this person to Vercel so they can deploy. Or just don’t.
How a historical GitHub Actions workflow handled shared staging and authorized production releases without purchasing a Vercel seat for every engineer.
5 min readBy Abdullah Raheel
Dashboard access is not the same as deployment access
At the time of this implementation, Vercel Pro cost $20 per seat. Three engineers would cost $60 each month and five or six would cost $100 to $120. The team kept one $20 project seat and moved deployment execution into GitHub Actions through the Vercel CLI.
The repository stored VERCEL_TOKEN, VERCEL_ORG_ID, and VERCEL_PROJECT_ID as secrets. Engineers could ship reviewed work through the normal trunk-based merge path without each receiving dashboard credentials.
Separate staging from production
I split deployment into two workflows. Merges to main updated staging; production required a manual release after QA from an authorized GitHub actor.
Pull request -> review -> merge to main
-> automatic staging build and deploy
-> QA
-> authorized production workflow
-> tag, release, deploy, Slack noticeRepository access did not automatically grant production access. The original workflow allowed Elusive7733 to trigger production while the rest of the team shipped through pull requests and staging.
Automate the environment used for review
Every push to main pulled the staging environment, built a prebuilt artifact with --target=staging, and deployed that exact output. A shared concurrency group used cancel-in-progress: true so a newer main commit replaced an obsolete queued or running staging deploy.
concurrency:
group: staging-deploy
cancel-in-progress: true
- run: vercel pull --yes --environment=staging --token=$VERCEL_TOKEN
- run: vercel build --target=staging --token=$VERCEL_TOKEN
- run: vercel deploy --prebuilt --target=staging --token=$VERCEL_TOKENKeep production deliberate
The manual production workflow accepted patch, minor, or major. With full Git history available, it read the latest tag, calculated the next semantic version, created and pushed the tag, pulled the production environment, built the prebuilt artifact, and deployed it.
A separate skip-tagging path reused the latest version for a redeploy. Recovery did not need to create a false new release number merely to rerun infrastructure.
on:
workflow_dispatch:
inputs:
version_type:
type: choice
options: [patch, minor, major]
skip_tagging:
type: boolean
default: falseLeave an operational trail
After a tagged release, gh release create --generate-notes produced the changelog. .github/release.yml grouped pull requests by label. The workflow appended deployment metadata and sent a formatted release through a Slack webhook.
I built an AI changelog generator first and deleted it three days later. GitHub already listed every merged pull request and link, so the model added code without adding useful release information.
Spend on the permission the system actually needs
The working sequence was simple: merge a reviewed pull request, deploy staging, verify it, then let an authorized actor trigger production. Version tags, GitHub releases, and Slack messages left a release trail outside the Vercel dashboard.
- Use repository and environment protection for the credentials that replace dashboard access.
- Separate automatic review deployments from deliberate production execution.
- Build once and deploy the prebuilt artifact for each environment.
- Treat native release notes as the default before adding another generation system.

