Quickstart
This guide covers the greenfield path: a fresh Next.js project that you want to shadow-and-canary from day one. For an existing project, see Migration (manual).
Time: about 10 minutes.
Prerequisites
- A Vercel account (Pro or Enterprise for Skew Protection; see Prerequisites)
- A GitHub account with GitHub Actions available
- Node.js 20 or later
pnpm,npm, oryarn
-
Clone the template
Terminal window git clone https://github.com/mus-inn/shadow-canarycd shadow-canary/examples/greenfieldnpm installOr use the GitHub template button on github.com/mus-inn/shadow-canary to create a new repo pre-wired.
-
Set up Vercel project
Import the repo in the Vercel dashboard. Then configure these settings in Project Settings:
Setting Value Production Branch productionAuto-assign Custom Production Domains OFF Deployment Protection Disabled (POC) or Protection Bypass enabled (prod) Skew Protection ON, 7 days [screenshot: Vercel Settings > Git panel with Production Branch field set to “production” and Auto-assign OFF]
Set the default branch in GitHub to
master(notmain). The canary cron workflow relies on running on the default branch. -
Create an Edge Config store
In the Vercel dashboard, go to Storage and create a new Edge Config store. Name it something like
shadow-config.Link the store to your project: in the store’s settings, click Connected Projects and add your project.
[screenshot: Vercel Storage > Edge Config > Connected Projects panel]
Copy the store ID — it looks like
ecfg_xxxxxxxxxxxx. You will need it for secrets. -
Seed the Edge Config
In the store’s Items tab, add one item:
- Key:
shadow-<your-repo-slug>-canary(e.g. for a repo namedmy-app, the key isshadow-my-app-canary) - Value (JSON):
{"deploymentDomainProd": "","deploymentDomainProdPrevious": "","deploymentDomainShadow": "","trafficShadowPercent": 1,"trafficProdCanaryPercent": 100,"shadowForceIPs": []}The workflows will overwrite the URL fields on every deploy. The empty strings here just ensure the key exists before the first push.
- Key:
-
Wire GitHub secrets
In your GitHub repo, go to Settings > Secrets and variables > Actions and add:
Secret Where to find it VERCEL_TOKENVercel Account Settings > Tokens (scope: team, no expiry) VERCEL_ORG_ID.vercel/project.json— theorgIdfield, or Vercel team settingsVERCEL_PROJECT_ID.vercel/project.json— theprojectIdfieldVERCEL_EDGE_CONFIG_IDEdge Config store ID from Step 3 ( ecfg_xxxx)SLACK_WEBHOOK_URLSlack app > Incoming Webhooks (optional — skip if you don’t use Slack) [screenshot: GitHub Settings > Secrets panel with the five secrets listed]
-
Wire Vercel environment variables
In Vercel Project Settings > Environment Variables, add these for Production and Preview environments:
Variable Value VERCEL_API_TOKENSame token as VERCEL_TOKENaboveVERCEL_ORG_IDSame as the GitHub secret VERCEL_EDGE_CONFIG_IDSame as the GitHub secret ADMIN_USERAdmin username (default: admin)ADMIN_PASSAdmin password — choose something strong ADMIN_SESSION_SECRETA long random string for signing session cookies Generate a session secret:
Terminal window node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" -
First deploys
Push to
masterto deploy the shadow slot:Terminal window git push origin masterThis triggers
deploy-shadow.yml, deploys the app, and writesdeploymentDomainShadowinto Edge Config. Watch the Actions tab — the first run takes about 90 seconds.Then push to
productionto deploy the production slot. Use[skip-canary]on the first push because there is no previous prod URL to fall back to:Terminal window git checkout productiongit merge master -m "chore: bootstrap production [skip-canary]"git push origin productionThis triggers
deploy-prod.yml, promotes the deploy to your custom domain, and setstrafficProdCanaryPercent: 100. -
Verify
Visit these three URLs (replace
your-domain.vercel.appwith your actual domain):URL What to check https://your-domain.vercel.app/Home page loads normally https://your-domain.vercel.app/debugShows branch, commit, deploy ID, and your bucket cookie https://your-domain.vercel.app/adminLogin with ADMIN_USER/ADMIN_PASS; status shows “stable”On the
/debugpage, click Force SHADOW — reload and the page should showmasteras the branch. Click Forcer PROD to return.
You’re done
Your project now has:
- A permanent 1% shadow slot on
masterreceiving real traffic. - A canary ramp on every merge to
production, with SLO checks every 15 minutes. - Auto-rollback if SLO fails, with Slack notification (if configured).
- A
/admindashboard to pause, resume, or cancel the canary.
Next steps:
- Connect a real SLO source (Sentry, Datadog, PostHog).
- Understand the routing logic — sticky sessions, cookie values, the bot bypass.
- Read about the three workflows and how to customize the ramp curve.