Overview

Vercel builds and deploys a Git repository on every push: the production branch goes to production, and every other branch gets its own preview deployment. This guide imports a project, sets environment variables, overrides build settings only where needed, attaches a domain, and checks previews. Platform-specific features (middleware, ISR, edge functions) are in vercel.

Prerequisites

  • A GitHub, GitLab, or Bitbucket repository, and a Vercel account.
  • Optional: the CLI (npm i -g vercel) for vercel env pull, vercel --prod, and debugging.

Steps

1. Import the project

In the dashboard choose Add New, Project, pick the repository, and Import. Vercel detects the framework (Next.js, Astro, Vite, and others) and fills in the build settings; check them before the first deploy.

2. Set environment variables

Add variables under Settings, Environment Variables, and choose which environments get each: Production, Preview, Development, or a custom environment. Scope a variable to one environment only when its value differs, such as a staging database for previews, and add branch-specific preview values where needed. Changes apply only to new deployments, so redeploy after editing. Never put secrets in variables that are exposed to the browser, such as those prefixed NEXT_PUBLIC_. vercel env pull writes the Development variables to .env.local, or to a file you name. See vercel-env-vars.

3. Override build settings only when the defaults are wrong

Typical reasons: a non-standard build script, a different output directory, or a strict install.

{
  "buildCommand": "npm run build:prod",
  "outputDirectory": "dist",
  "installCommand": "npm ci"
}

Put this in vercel.json, or set the same fields under Settings, Build and Development Settings.

4. Attach a custom domain

Under Settings, Domains, Add Domain. Use the records Vercel shows for your project: an A record for an apex domain, and a project-specific CNAME for a subdomain. Do not copy another project’s values. If you add an apex domain, Vercel suggests adding www too; add both and redirect one to the other. If DNS is on Cloudflare, set the record to DNS only (grey cloud) until the domain validates; a proxy in front of Vercel can interfere with validation and certificate issuance.

5. Use preview deployments

Every push to a non-production branch gets a unique commit URL, <project>-<hash>-<scope>.vercel.app, and a stable branch URL, <project>-git-<branch>-<scope>.vercel.app, which is the one to share with reviewers. Both are publicly reachable unless Deployment Protection is on.

Verify it worked

curl -sI https://example.com | head -1                                   # HTTP/2 200
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -issuer -dates
git checkout -b test/preview && git commit --allow-empty -m "test: preview" && git push -u origin test/preview

The pull request gets a comment with the preview URL.

Common errors

  • The build fails with “command not found”. The tool is not in dependencies or devDependencies; add it.
  • A variable is undefined at runtime. It is scoped to the wrong environment, or it was added after the deployment; redeploy.
  • The domain shows “Invalid Configuration”. A conflicting A, AAAA, or CNAME record exists for the same hostname, or the values were copied from another project; compare against the values in Domains.
  • A single-page app returns 404 on deep links. Add a rewrite: "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }] in vercel.json.

FAQ

Why is my Vercel environment variable undefined at runtime?

It is scoped to the wrong environment, or it was added after the deployment. Changes apply only to new deployments, so redeploy after editing.

Are Vercel preview deployments public?

Yes. Both the commit URL and the branch URL are publicly reachable unless Deployment Protection is on.

Should I proxy my Vercel domain through Cloudflare?

Set the record to DNS only (grey cloud) until the domain validates, because a proxy in front of Vercel can interfere with validation and certificate issuance.

Why does my Vercel domain show Invalid Configuration?

A conflicting A, AAAA, or CNAME record exists for the same hostname, or the values were copied from another project; use the records Vercel shows in Domains for this project.

Add a rewrite in vercel.json that sends /(.*) to /index.html.