Building with AI · 11 min read

Deploying on Vercel without surprises

Projects, environments, and domains explained plainly, preview deploys as a habit, and the bill-shock traps to avoid.

Vercel makes shipping a Next.js app feel almost too easy, and that ease is exactly where the surprises hide. The deploy step is rarely the problem. An unexpected bill, a domain pointed at the wrong thing, or a preview URL somebody assumed was private, that is where teams actually get caught out. None of that is complicated once you know the three concepts underneath it: projects, environments, and domains.

Projects, environments, and domains, plainly

A Vercel project is one app connected to one git repository. Every app we run, this marketplace included, is its own project, even though several of them live in the same monorepo. Point a project's root directory at the right folder and Vercel treats that folder as the whole app from then on.

A monorepo with several apps inside it does not need several repositories to get several Vercel projects. Create one Vercel project per app and set each project's root directory to the right subfolder; Vercel builds and deploys each app on its own schedule from then on, watching only the paths that belong to it. That is the setup behind every app we run, including this one.

Inside a project, Vercel keeps three kinds of environments apart. Production is whatever is on your main branch, live on your real domain. Preview is every other branch and every pull request, each one getting its own throwaway URL the moment you push. Development is your own machine, running locally, talking to neither of the other two unless you tell it to. Environment variables can be set separately for each, which is exactly how a production database key stays out of a preview deploy that someone might share in Slack.

Domains sit on top of all that. A custom domain attaches to Production by default; preview deploys get a random subdomain under vercel.app unless you deliberately configure otherwise. Knowing which environment your domain is pointed at is worth checking any time something looks live but is not updating, because that mismatch is a common source of “why isn't my change showing up” confusion.

Preview deploys as a workflow

The habit worth building is treating every pull request as a real, clickable version of the app rather than a diff you read on screen. Open a PR, Vercel builds it, and you get a URL that behaves exactly like production, running against whatever that branch actually contains. Click through it before you merge.

This is where most of the value shows up in practice: a design change gets reviewed on a real page instead of a screenshot, a client gets a link to look at their actual site before it goes live, and a bug that only appears with real navigation gets caught before it reaches anyone who matters. We run our whole PR loop this way, screenshotting the preview itself, critiquing it, fixing it, and merging only once the deployed version looks right.

Attaching a real domain without the DNS headache

Pointing your own domain at a Vercel project is small enough to finish in one sitting: two DNS records and a short wait for propagation. An apex domain like yourbusiness.com needs an A record pointed at Vercel's IP; a subdomain like www needs a CNAME pointed at the address Vercel gives you when you add the domain in project settings. Add both if you want the site to answer on either. Vercel issues and renews the SSL certificate automatically once the records resolve, so there is no separate certificate step to remember or forget.

The one setting worth deciding on purpose is which version, the apex or the www subdomain, is canonical, and redirecting the other to it. Search engines and browsers treat yourbusiness.com and www.yourbusiness.com as different addresses unless you tell them otherwise, and Vercel's domain settings let you pick one and redirect the other in a couple of clicks.

Rolling back without panic

Every deploy on Vercel is a separate, immutable build, which means the previous good version of your site never disappears, it just stops being the one your domain points at. If a deploy breaks something in production, skip the rushed hotfix commit. Open the project's deployments list, find the last deploy that worked, and promote it to production. That takes effect in seconds and buys you time to fix the actual problem calmly rather than live on the real site.

Get in the habit of checking a deploy's preview URL before promoting it, even for changes that feel small. A build that succeeds does not guarantee a page that renders correctly. The few seconds it takes to click through a preview is cheap insurance against exactly the kind of production surprise this guide is about avoiding.

This is also where team size starts to matter. A solo project can get away with promoting straight from the deployments list. Once more than one person can deploy, agree on who is allowed to promote to production and when, the same basic discipline any team applies to its main branch, just extended one step further to cover the domain that customers actually see.

The bill-shock traps, and how to avoid them

Vercel's free tier is genuinely generous, which is part of the trap: teams build habits on the free tier and then scale past it without noticing where the meter starts running. Three places it tends to happen:

  • Serverless function usage. Every API route and server action runs as a function, billed on execution time and invocation count. An inefficient route that queries a slow database on every request costs more than the same route with a bit of caching, and the difference only shows up once traffic is real.
  • Image optimization. Vercel's image pipeline resizes and re-encodes images on request, and it's billed by source image count and transformations on top of bandwidth. A page that generates a new image variant for every combination of size and format can rack up transformations fast if you're not deliberate about how many sizes you actually need.
  • Idle resources tied to every environment. A database or third-party API connected to preview deploys means every branch you open can hit that same paid resource. Multiply that by a busy week of pull requests and a bill meant for one production app quietly becomes a bill for a dozen preview copies of it too.

The fix for all three is the same kind of habit: set a spend management cap in your Vercel billing settings so a runaway week alerts you instead of silently charging you, keep an eye on the usage tab before it becomes a surprise on the invoice, and actually decide which resources preview deploys are allowed to touch rather than assuming they inherit production's access by default.

One more habit worth adopting early: delete or let expire the preview deploys and old projects you are not using. They rarely cost much individually, but a monorepo with a dozen apps and years of merged branches accumulates clutter that makes the real usage harder to read, even when it is not the thing driving the bill.

We deploy every client site and every internal tool this way, one project per app, previews for every change, production reserved for what has actually been reviewed. If you want your deployment setup audited or built out properly, that is part of our AI consulting work, and the membership includes the deeper playbook on our full deploy checklist.