Deploy to Vercel: From Local to Live in 5 Minutes
Complete Vercel deployment guide -- connect GitHub, configure env vars, custom domains, serverless functions, preview deployments, and the CLI.
You've built something locally. It works on localhost:3000. Now what? The gap between "works on my machine" and "live on the internet" used to involve server provisioning, Nginx configs, SSL certificates, and a lot of praying. Vercel collapsed that gap to basically nothing.
Push to GitHub, Vercel builds and deploys. That's genuinely it for most projects. But there's a lot more going on under the hood, and understanding it means you can use Vercel for more than just simple landing pages.
What Vercel Actually Is
Vercel is a cloud platform optimized for frontend frameworks and serverless functions. It's built by the team behind Next.js, so the integration there is best-in-class, but it works with any framework -- React, Vue, Svelte, Astro, plain HTML, whatever.
What makes it different from traditional hosting:
- Edge network -- your site is served from 30+ global locations, not one server
- Serverless functions -- backend code that runs on demand, no servers to manage
- Preview deployments -- every pull request gets its own live URL
- Zero config -- it detects your framework and configures the build automatically
Connecting Your GitHub Repository
The fastest path to deployment:
- Go to vercel.com and sign up with GitHub
- Click "Add New Project"
- Select your repository
- Vercel auto-detects the framework and suggests build settings
- Click "Deploy"
package.json, figures out the build command (npm run build), identifies the output directory, and handles everything.
If your project has a non-standard setup, you can override:
- Build Command:
npm run build(or whatever your build script is) - Output Directory:
out,dist,build,.next-- depends on your framework - Install Command:
npm installby default, change topnpm installoryarnif needed - Root Directory: for monorepos, point to the specific package
Automatic Deployments
Once connected, every push triggers a deployment:
- Push to
main(or your production branch) -> production deployment at your domain - Push to any other branch -> preview deployment at a unique URL
- Open a pull request -> preview deployment with a comment on the PR showing the URL
You can configure which branches trigger deployments in the project settings. Want to ignore a branch? Add it to the ignore list. Want to only deploy from specific branches? Set that up too.
Environment Variables
Most real projects need environment variables -- API keys, database URLs, feature flags. Vercel handles these in the project settings under "Environment Variables."
You can scope variables to specific environments:
- Production -- only available in production deployments
- Preview -- only available in preview/branch deployments
- Development -- available when using
vercel devlocally
DATABASE_URL=postgresql://user:pass@host/db (Production)
DATABASE_URL=postgresql://user:pass@host/dev_db (Preview)
NEXT_PUBLIC_API_URL=https://api.myapp.com (Production)
NEXT_PUBLIC_API_URL=https://staging.api.myapp.com (Preview)
Variables prefixed with NEXT_PUBLIC_ are exposed to the browser in Next.js projects. Everything else stays server-side. This is a Next.js convention, not a Vercel one.
You can also use the CLI to manage env vars:
# Add a variable
vercel env add DATABASE_URL production
# List all variables
vercel env ls
# Pull env vars to a local .env file
vercel env pull .env.local
That last command is extremely useful. Instead of manually copying env vars from the dashboard, vercel env pull downloads them for local development.
Custom Domains
Every Vercel deployment gets a .vercel.app URL automatically. For a real project, you want your own domain.
In your project settings, go to "Domains" and add your domain:
- Add
myapp.com - Vercel gives you DNS records to add at your registrar
- Add the records (usually a CNAME or A record)
- SSL certificate is provisioned automatically
myapp.com -> production
www.myapp.com -> redirects to myapp.com (configurable)
staging.myapp.com -> preview branch
You can also point a specific branch to a domain. Want staging.myapp.com to always show the staging branch? Set that in domain configuration.
DNS propagation can take anywhere from minutes to hours. Vercel shows the status in the dashboard so you know when it's ready.
Serverless Functions
This is where Vercel goes beyond static hosting. You can write backend code that runs on demand.
For Next.js projects using the App Router, your Route Handlers are automatically deployed as serverless functions:
// app/api/hello/route.ts
import { NextResponse } from "next/server";
export async function GET() {
return NextResponse.json({ message: "Hello from the edge" });
}
export async function POST(request: Request) {
const body = await request.json();
// Talk to a database, call an API, whatever
const result = await processData(body);
return NextResponse.json(result);
}
For non-Next.js projects, create an api/ directory in your project root:
// api/hello.ts
import type { VercelRequest, VercelResponse } from "@vercel/node";
export default function handler(
req: VercelRequest,
res: VercelResponse
) {
res.status(200).json({ message: "Hello" });
}
Serverless functions support Node.js, Python, Go, and Ruby. Each function gets up to 10 seconds of execution time on the free tier (configurable on paid plans).
# api/process.py
from http.server import BaseHTTPRequestHandler
import json
class handler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers["Content-Length"])
body = json.loads(self.rfile.read(content_length))
result = {"processed": True, "input": body}
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(json.dumps(result).encode())
Edge Functions
Edge functions run closer to the user -- on Vercel's edge network instead of a single region. They have lower latency but more constraints (no Node.js filesystem, limited APIs).
// middleware.ts (runs at the edge by default in Next.js)
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
// Redirect based on geography
const country = request.geo?.country;
if (country === "DE") {
return NextResponse.redirect(new URL("/de", request.url));
}
return NextResponse.next();
}
You can also explicitly mark a route handler as an edge function:
// app/api/fast/route.ts
export const runtime = "edge";
export async function GET() {
return new Response(JSON.stringify({ fast: true }), {
headers: { "Content-Type": "application/json" },
});
}
Edge functions are great for authentication checks, redirects, A/B testing, and any logic that benefits from being geographically close to the user. They're not great for database queries (unless your database is also at the edge, like Turso or Neon's edge).
Preview Deployments
This is one of Vercel's killer features that doesn't get enough attention. Every git branch and pull request gets a unique deployment URL.
When you open a PR on GitHub, Vercel:
- Builds the branch
- Deploys it to a unique URL like
my-project-git-feature-branch-username.vercel.app - Adds a comment to the PR with the preview URL
- Runs any checks you've configured
- Designers can review UI changes without running the project locally
- QA can test features in isolation
- Stakeholders can preview changes before they hit production
- You can share a working URL in a Slack thread
The Vercel CLI
The CLI is useful for local development and quick deployments without pushing to GitHub.
# Install
npm install -g vercel
# Login
vercel login
# Deploy the current directory
vercel
# Deploy to production
vercel --prod
# Run the development server with Vercel features
vercel dev
# Link a local directory to a Vercel project
vercel link
vercel dev is particularly useful -- it simulates the Vercel environment locally, including serverless functions and environment variables. Your API routes work exactly as they would in production.
Quick deployment workflow for testing:
# Make changes, deploy a preview
vercel
# Vercel outputs a preview URL
# Test it, share it, whatever
# Happy with it? Promote to production
vercel --prod
Monorepo Support
If your repository contains multiple projects (a common setup with turborepo or nx), Vercel handles it:
- Create separate Vercel projects for each app
- In each project's settings, set the Root Directory to the app's path (e.g.,
apps/web) - Configure Ignored Build Step to only rebuild when relevant files change
# vercel-ignore.sh
#!/bin/bash
# Only build if files in this app or shared packages changed
npx turbo-ignore
Or use Vercel's built-in Git diff:
git diff HEAD^ HEAD --quiet -- apps/web/ packages/shared/
This returns exit code 0 (skip build) if no files changed in those directories, or exit code 1 (proceed with build) if they did.
Deployment Configuration: vercel.json
For advanced configuration, create a vercel.json in your project root:
{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"framework": "nextjs",
"regions": ["iad1"],
"headers": [
{
"source": "/api/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "s-maxage=60, stale-while-revalidate=600"
}
]
}
],
"redirects": [
{
"source": "/blog/:slug",
"destination": "/posts/:slug",
"permanent": true
}
],
"rewrites": [
{
"source": "/api/:path*",
"destination": "https://my-backend.com/:path*"
}
]
}
You can configure headers, redirects, rewrites, function regions, and more. This file is version-controlled, which is better than configuring everything through the dashboard.
Common Mistakes
Not scoping env vars properly. If an API key only exists in "Production" but your preview deployment needs it, the preview build will fail silently (the variable will just beundefined). Always check which environments your variables are available in.
Ignoring build logs. When a deployment fails, the build logs tell you exactly why. Most failures are: missing environment variables, wrong Node.js version, or dependency conflicts. Read the logs.
Not setting the Node.js version. Vercel defaults to Node 20, but if your project needs a specific version, set it in package.json:
{
"engines": {
"node": "20.x"
}
}
Oversized serverless functions. There's a 50MB limit (compressed) for serverless functions. If you're bundling large dependencies, use dynamic imports or move heavy processing to a separate service.
Not using vercel env pull. Manually copying environment variables between Vercel and your local .env file leads to inconsistencies. Use the CLI command instead.
What's Next
Vercel keeps adding features -- Vercel Postgres, Vercel KV (Redis), Vercel Blob storage, analytics, speed insights. Whether you use those or bring your own services, the deployment pipeline stays the same: push code, get a URL.
For most frontend and full-stack projects, Vercel removes an enormous amount of infrastructure complexity. You can focus on building features instead of configuring servers.
For more deployment guides and web development tutorials, check out CodeUp.