Ship It: Supabase + Vercel · lesson 2 of 3
Deploying on Vercel
Vercel's deployment model in one sentence: every deploy is immutable and gets its own URL; "production" is just a pointer to one of them. Most operational commands are pointer manipulation.
Core commands
vercel # deploy → unique preview URL
vercel --prod # deploy → production
vercel --prebuilt # deploy artifacts built elsewhere (CI pattern:
# `vercel build` in CI, then upload the output)
vercel link # bind cwd to a project → .vercel/project.json
vercel link writes .vercel/project.json (project + org IDs) — that file is how later CLI calls know which project you mean.
Environment variables
Env vars are scoped per environment: Development / Preview / Production.
vercel env add MY_KEY production # prompts for value
vercel env ls
vercel env rm MY_KEY
vercel env pull .env.local # download Development-scope vars locally
Two rules that cause real incidents:
NEXT_PUBLIC_prefix — inlined into client bundles at build time. Anything under it is public, and changing it requires a rebuild (avercel rollbackwon't pick up new values; see below).- Server-only secrets (e.g. the
sb_secret_key from supabase-for-app-devs) must not carry the prefix.
Custom domains
vercel domains add example.com
| Case | DNS record |
|---|---|
Apex (example.com) | A record to Vercel's IP |
Subdomain (app.example.com) | CNAME → cname.vercel-dns.com |
Wildcard (*.example.com) | requires Vercel nameservers |
SSL certificates are provisioned and renewed automatically for every domain.
Cron jobs
Declare in vercel.json:
{ "crons": [{ "path": "/api/cron", "schedule": "0 5 * * *" }] }
Semantics:
- Vercel sends a GET request to that path on the production deployment per the cron expression.
- Secure the endpoint: Vercel automatically sends
Authorization: Bearer $CRON_SECRET(if you've set theCRON_SECRETenv var) — verify it, or anyone who finds the URL can trigger your job. - The request carries an
x-vercel-cron-scheduleheader identifying the schedule.
export async function GET(req: Request) {
if (req.headers.get("authorization") !== `Bearer ${process.env.CRON_SECRET}`)
return new Response("unauthorized", { status: 401 });
// ... run the job
}
Promote vs rollback
| Command | What it does | Env vars |
|---|---|---|
vercel promote <url> | rebuilds the deployment with current production env, then points production at it | fresh |
vercel rollback | instant pointer flip to a previous deployment | frozen at that deployment's build time |
Rollback is the incident tool (seconds, no build); promote is the "this preview is good, ship it properly" tool. Remember the interaction with NEXT_PUBLIC_: a rollback resurrects old inlined values.
Key terms
- Preview deployment — the immutable, uniquely-URL'd deployment created by plain
vercel(or a git push); the review artifact. - vercel --prebuilt — deploy output already produced by
vercel build, so CI builds and Vercel only hosts; keeps build environment under your control. - vercel link / .vercel/project.json — the binding between a local directory and a Vercel project that the CLI reads on every command.
- Environment scopes — Development / Preview / Production targeting for each env var;
vercel env pullmaterializes development vars into.env.local. - NEXT_PUBLIC_ prefix — marks an env var for inlining into the client JavaScript bundle at build time; public by definition, rebuild-required to change.
- cname.vercel-dns.com — the CNAME target for subdomains; apex domains use an A record instead, wildcards require Vercel nameservers.
- Vercel cron job — a
vercel.jsoncronsentry causing scheduled GETs to a path on production, authenticated via the auto-sentAuthorization: Bearer $CRON_SECRET. - x-vercel-cron-schedule — request header identifying which cron schedule triggered the invocation.
- vercel promote — point production at a deployment after rebuilding it with current production env vars.
- vercel rollback — instant pointer flip to a prior deployment with no rebuild; env values remain whatever was inlined when it was built.
See also
- supabase-for-app-devs — the backend these deploys talk to
- how-this-site-works — cron + deploy automation in practice