Deploy a Next.js Application on Vercel
Import a Next.js repository into Vercel, configure builds and environments, connect a domain, inspect logs, and verify production behavior.
On this page
A Next.js application that builds locally can still fail on Vercel because the platform checks out a different commit, starts in the wrong project root, uses a clean dependency install, runs on a case-sensitive filesystem, or receives different environment variables. Treat the deployment as a reproducible build with its own environment rather than a copy of the local machine.
Confirm the repository can build cleanly
Before importing it, use the package manager and lockfile committed to the repository:
npm ci
npm run buildThe commands are examples for an npm project. If the repository uses pnpm, Yarn, or Bun, keep one authoritative lockfile and configure the matching install process. Do not commit .env.local, build output, or a local node_modules directory.
Review the supported Node.js version, framework version, and every build-time dependency. A package available globally on a laptop will not exist in a clean Vercel build unless the project declares it.
Import the Git repository
Vercel's Git deployment documentation supports connected repositories from GitHub, GitLab, Bitbucket, and Azure DevOps. In the dashboard:
- Create a project and import the intended repository.
- Choose the owning account or team deliberately.
- Select the root directory containing this Next.js app's
package.json. - Confirm the detected Next.js framework preset.
- Review install, build, development, and output settings.
- Add required environment variables for the first deployment.
- Deploy and read the build log rather than assuming framework detection was correct.
For a monorepo, the root might be apps/web, not the repository root. The package manager must still be able to reach workspace configuration and lockfiles according to the monorepo layout.
Vercel normally supplies appropriate defaults for Next.js. Override install or build commands only when the repository scripts require it. A custom output directory copied from a static-site tutorial can break server-rendered routes and functions.
Separate Preview and Production configuration
Connected Git repositories typically create Preview deployments for non-production branches and Production deployments from the configured production branch. Each deployment has a unique URL. Use Preview for review and integration testing; do not point it at production databases merely for convenience.
Vercel lets an environment variable target Production, Preview, Development, or configured custom environments. Adding or changing a value applies it to a subsequent deployment; redeploy the intended commit after a configuration change.
Define separate values where the environment truly differs:
DATABASE_URL
INTERNAL_API_URL
NEXT_PUBLIC_SITE_URL
NEXT_PUBLIC_API_BASE_URLThese are names only, not real values. Put credentials in Vercel's protected environment settings and scope access to the project/team. Do not print variables in build or runtime logs.
Understand server and client variables
Next.js keeps ordinary environment variables on the server. Variables prefixed with NEXT_PUBLIC_ are exposed to browser JavaScript and inlined into the client bundle at build time, as the official Next.js environment guide explains.
Never prefix a database URL, private API key, signing secret, or storage credential with NEXT_PUBLIC_. The prefix is an exposure decision, not just a naming convention.
Public values are frozen when next build runs. Changing NEXT_PUBLIC_API_BASE_URL in the dashboard does not rewrite an already-built bundle; trigger a new deployment. Server-side runtime availability depends on how the route is rendered and the deployed runtime, so verify whether a value is needed during build, static generation, or request handling.
API base URLs and CORS
Prefer relative calls such as /api/contact when the API is part of the same Next.js deployment. They automatically follow the current Preview or Production origin.
When the API is hosted separately, use the correct environment-specific public base URL and configure the API's CORS policy for the actual frontend origins. Preview deployments have changing hostnames, so avoid a permissive * response with credentials. Use a reviewed preview-domain policy or stable preview domain. The Express and Next.js CORS guide covers preflight, credentials, and origin validation.
Server-to-server requests are not governed by browser CORS, but they still require reachable DNS, TLS, authentication, and timeouts. Decide whether a fetch runs during the build or per request; a private API reachable from runtime may be unreachable during static generation.
Configure custom domains and DNS
Add the domain under the Vercel project's domain settings. Vercel then displays the required DNS record or nameserver configuration for that domain and verifies it. Use the exact current instructions shown for the project because apex and subdomain records, existing DNS providers, and account verification can differ.
Preserve mail and verification records when editing DNS. Choose one canonical hostname, redirect alternatives, and verify HTTPS after DNS resolves. Never publish the domain's DNS-provider credential or Vercel token.
Configure remote images
Remote images used by next/image must match a specific images.remotePatterns entry:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "images.example.test",
port: "",
pathname: "/public/**",
search: "",
},
],
},
};
export default nextConfig;The hostname is a reserved example, not a real service. Scope patterns to the actual trusted origin and path. Configuration changes require a rebuild. If production returns 400 for optimized images, follow the Next.js Image 400 troubleshooting guide.
Build logs and runtime logs answer different questions
Build logs cover checkout, dependency installation, framework detection, next build, type checking, and static generation. Use them for missing packages, incorrect root directories, TypeScript errors, unavailable build-time data, and out-of-memory builds.
Runtime logs cover requests to server functions, route handlers, middleware, and rendered server routes. Use them for request exceptions, database connectivity, timeouts, and environment values being absent at runtime. Sanitize logs: do not emit request authorization headers, cookies, tokens, database URLs, or submitted personal data.
Check the deployment and function region, runtime type, duration and memory limits against current plan documentation. Behavior and limits can change by Vercel product and plan.
Persistent upload storage
Do not store permanent user uploads in a function's local filesystem or the checked-in public directory. A deployment is immutable, and runtime writable space is not a shared durable media store across invocations or deployments. Use an object store such as Vercel Blob or another provider with explicit access and retention policy. See Store and Serve User-Uploaded Images in Node.js for public/private storage boundaries.
Why local succeeds while production fails
- A required environment variable exists only in
.env.local. - A
NEXT_PUBLIC_value was changed without rebuilding. - The wrong monorepo root or lockfile was selected.
- A filename import differs only by letter case.
- A development dependency is incorrectly omitted from the production build.
- Code assumes a persistent local disk or long-running Node.js process.
- Static generation calls an API or database unavailable from the build environment.
- The deployed Node.js/runtime version differs from local development.
- A remote image host is missing from
remotePatterns. - The separate API rejects the Production or Preview origin through CORS.
Verify the production deployment directly
Do not verify only the dashboard status or the homepage. Open the Production URL directly in a private browser session and test:
- dynamic and deeply nested routes, including refreshes;
- authenticated and unauthenticated states;
- route handlers and separately hosted APIs;
- optimized remote images and static assets;
- metadata,
robots.txt, andsitemap.xml; - redirects, canonical domain, HTTPS, and response errors;
- database/network behavior under the production environment;
- runtime logs for the exact request time.
A redeploy reruns the selected commit with the currently selected configuration. Confirm which deployment is assigned to the production domain rather than assuming the latest build is live.
Verification checklist
- The imported repository, branch, project root, framework, and lockfile are correct.
- Install and production build commands succeed in a clean environment.
- Preview and Production variables and external services are separated.
- No secret uses
NEXT_PUBLIC_or appears in build/runtime logs. - Custom-domain DNS and HTTPS match the instructions shown by Vercel.
- Remote image patterns and separate-API CORS policies match production URLs.
- Permanent uploads use durable external storage.
- Direct tests cover dynamic routes, handlers, images, metadata, and production logs.
References
Documentation checked on 2026-08-12:
Related writing
- Set Up Google Analytics 4 and Search Console for Next.jsAdd consent-aware GA4 measurement and configure Search Console ownership, sitemaps, inspection, and indexing checks for a Next.js site.
- Edge runtime explained — locality, isolation, and the limits of v8 snippetsWhat shifts when handlers run closer to users: cold starts, memory ceilings, cryptography constraints, and why edge does not magically delete physics.
- Deploy a Node.js Application with PM2 and NginxBuild and run a Node.js application with PM2, proxy it through Nginx, preserve client headers, and verify the deployment safely.