Deploying Next.js to Vercel is the closest thing to a one-click experience in web dev — but “almost zero config” is not “zero config”. The defaults are right for 90% of cases; the last 10% (env vars, custom domain, image domains, function regions) is where indie devs lose half a day.
Background
Vercel is the company behind Next.js, so the integration is unmatched — auto-detected framework, preview deploys on every PR, edge-deployed static assets, and a free Hobby tier that covers most indie launches. The trade-off is usage-based billing once you scale and lock-in to Vercel-specific features (ISR, image optimization at the edge).
How to tell
- You have a Next.js project in a GitHub / GitLab / Bitbucket repo.
- You want preview URLs per PR without setting up CI.
- You are comfortable with usage-based billing once Hobby limits are hit.
Step by step
-
Push your Next.js project to GitHub. If you do not have a git history yet:
git init git add . git commit -m "initial commit" # With gh CLI installed: gh repo create my-next-app --public --source=. --push # Otherwise create the repo at github.com first, then: git remote add origin https://github.com/<you>/my-next-app.git git branch -M main git push -u origin main -
Sign in at vercel.com with the same Git provider (OAuth), click Add New → Project, find the repo, click Import. Vercel auto-detects Next.js and fills in:
Framework Preset: Next.js Build Command: next build Output Directory: .next (leave empty — automatic) Install Command: npm install -
On the same import screen, paste env vars under Environment Variables, one
KEY=VALUEper line:DATABASE_URL=postgresql://user:pass@host:5432/db NEXT_PUBLIC_SITE_URL=https://yoursite.com RESEND_API_KEY=re_xxxxxxxxxxxxxxxxUse the checkboxes on each row to pick environments (Production / Preview / Development). The same key can hold different values per environment. Keep a
.env.localfor local dev — Vercel does not read.env.local, it only reads what is in the dashboard. -
Click Deploy. First build usually takes 60–120 seconds. You get a
<project>-<hash>.vercel.appURL. -
Open the generated
*.vercel.app. DevTools → Console — watch for hydration errors (Hydration failed because the initial UI does not match what was rendered on the server). DevTools → Network, click any_next/static/*asset and check headers:x-vercel-cache: HIT # static assets are served from the edge age: 123 # seconds since cache fill -
Add the custom domain. Settings → Domains → Add, enter
yoursite.com, then add the DNS records Vercel shows at your DNS provider:Type Name Value A @ 76.76.21.21 CNAME www cname.vercel-dns.comOn Cloudflare: switch proxy to DNS only (grey cloud) so Vercel can issue its own SSL cert — otherwise you get SSL handshake errors. Verify:
dig yoursite.com +short # should return 76.76.21.21 curl -sI https://yoursite.com | head -5 # HTTP/2 200 # server: Vercel -
Configure the
next/imageremote allowlist innext.config.js(required to load external images, otherwiseInvalid src propat runtime):// next.config.js /** @type \{import('next').NextConfig\} */ const nextConfig = \{ images: \{ remotePatterns: [ \{ protocol: 'https', hostname: 'images.unsplash.com' \}, \{ protocol: 'https', hostname: 'cdn.yoursite.com' \}, ], \}, \}; module.exports = nextConfig; -
(Optional) Set the function region. Default is
iad1(Virginia). For Asia users, switch tohnd1(Tokyo) orsin1(Singapore). Createvercel.jsonin the project root:\{ "functions": \{ "app/api/**": \{ "maxDuration": 10, "regions": ["hnd1"] \} \} \}Or use the edge runtime per route in the App Router:
// app/api/hello/route.ts export const runtime = 'edge'; -
Verify PR previews work. Push a branch:
git checkout -b test-preview echo "<!-- test -->" >> README.md git commit -am "test preview" git push -u origin test-preview gh pr create --fillVercel posts a
<branch>-<hash>.vercel.apppreview URL as a PR check. Reviewers click straight into the per-branch deployment.
Common pitfalls
- Forgetting environment variables and getting
undefinedin production for what worked locally — Vercel does not read.env.local. - Setting
output: 'export'and being surprised that image optimization, API routes, and middleware no longer work. - Not configuring
images.remotePatternsinnext.config.js—next/imagewill refuse to optimize external images you do not allowlist. - Leaving function region as default (
iad1) when most users are in another continent — set region invercel.jsonorexport const runtime = 'edge'. - Treating preview URLs as production — they have the same compute limits but different env vars, so test before promoting.
Who this is for
Indie devs deploying a Next.js project for the first time, or anyone wanting CI/CD without operating a pipeline.
When to skip this
Plain static sites with high bandwidth needs (cheaper on Cloudflare Pages or Firebase Hosting), or projects already on AWS / GCP with infrastructure to share.
FAQ
- Do I have to use Vercel for Next.js?: No. Next.js runs on Node anywhere — AWS, Cloudflare (via OpenNext), self-hosted. But Vercel has the deepest integration and you give up some features moving off.
- Is the Hobby tier really free?: Free for non-commercial use with bandwidth and function-execution caps. Commercial or team use needs Pro ($20/user/month in 2026).
- Does Vercel auto-deploy on every push?: Yes —
maindeploys to production, other branches deploy to preview URLs. You can disable per-branch in Settings. - Can I roll back?: Yes — go to Deployments, find the previous good build, click “Promote to Production”. Instant rollback.