Claude Fable 5.1 & GPT-6 Astra packages are live

Vercel

Free

Deploying to Vercel — environment configuration, serverless and edge constraints, connection pooling, caching, preview deployments and cost control.

198 lines8.8 KB Sarvam Ai DevOps
targetModels
Sarvam-105BSarvam-30BSarvam FamilyFuture Sarvam Models
name
vercel
category
DevOps
description
Deploying to Vercel — environment configuration, serverless and edge constraints, connection pooling, caching, preview deployments and cost control.
license
MIT
author
Agent.md maintainers
last-verified
reviewed-by
unreviewed
<!-- Generated from models/_canonical by scripts/build-model-variants.js. Edit the canonical source, not this file. Behavioural profile for Sarvam: scripts/model-profiles.json -->

#Locale

Examples use Indian conventions: ₹ amounts, IST, dd/mm/yyyy, Aadhaar and DPDP Act where a standard mentions identity or privacy law. Keep them when you copy an example.


#Purpose

Rules for running an application on Vercel. The platform removes most deployment work; what remains is the set of constraints its execution model imposes — statelessness, cold starts, connection limits, and a build step that inlines values you may not want inlined.

Framework specifics are Backend/nextjs and Frontend/nextjs.


#Environment variables: build-time versus runtime

PrefixAvailable inBaked into the client bundle
NEXT_PUBLIC_*Browser and serverYes, at build time
Everything elseServer onlyNo
  • Never prefix a secret with NEXT_PUBLIC_. It is inlined into JavaScript served to every visitor, and rotating it requires a rebuild.
  • NEXT_PUBLIC_* values are captured at build time. Changing one in the dashboard does nothing until a redeploy — a recurring source of "I changed it and nothing happened".
  • Scope variables per environment (Production, Preview, Development). A preview deployment holding production credentials means every pull request can write to production.
  • Validate all variables at startup and fail the build or boot on a missing one. → DevOps/environments

#Serverless constraints

Every request may hit a cold instance. There is no shared process state.

Assumption that breaksRealityFix
In-memory cachePer-instance, discarded constantlyRedis / KV
In-memory rate limiterResets per instanceShared store → API/rate-limiting
Background work after the responseInstance is frozenwaitUntil, or a queue
Long-running requestHard execution limitBackground job → Backend/background-jobs
Local filesystem writesRead-only except /tmp, ephemeralObject storage
Cron in-processNot running between requestsVercel Cron
WebSocket serverNot supported by functionsA managed realtime service

Database connections are the classic failure. Each concurrent function instance opens its own connection, and a traffic spike exhausts max_connections in seconds:

ini
DATABASE_URL="postgres://…/db?pgbouncer=true&connection_limit=1&pool_timeout=20"
DIRECT_URL="postgres://…/db"     # migrations bypass the pooler

Use a transaction-mode pooler (PgBouncer, Supavisor, Neon or Prisma Accelerate), instantiate the client once at module scope, and never inside a handler. → Database/prisma


#Node runtime or Edge runtime

NodeEdge
APIsFull Node standard libraryWeb APIs only
Cold startHigherVery low
LocationRegion-pinnedDistributed
Database driversWorkMostly do not (no TCP)
Size limitLargerSmall bundle required
ts
export const runtime = "nodejs";     // declare it; do not rely on the default

Edge suits middleware, redirects, geolocation, header rewriting and auth checks. Anything using a database driver, a Node built-in, or a large dependency belongs on Node.

Place functions in the region nearest the database. An edge function in Sydney querying a database in Frankfurt pays that round trip on every query — edge compute helps only when the data is also close.


#Caching and revalidation

  • Static and ISR pages are served from the edge; dynamic ones execute per request. Read the next build output and confirm each route's mode is what you intended. A personalised route rendered statically is a data-leak bug, not a performance note.
  • Use revalidateTag/revalidatePath after mutations; stale content after a successful write is what users report as "it didn't save".
  • Set Cache-Control: no-store on authenticated responses. A cached authenticated response served to another visitor is the worst failure mode here.
  • Static assets are content-hashed and cached immutably by the platform — do not fight it with custom headers.

#Previews, protection and cost

  • Every pull request gets a preview deployment. Treat them as publicly reachable unless protected: enable Deployment Protection (Vercel Authentication or a password) for anything containing real data.
  • Give previews their own database, or a seeded branch database. Pointing previews at production means an untested migration runs against real data.
  • Deployments are immutable, so rollback is instant: promote a previous deployment rather than redeploying. → DevOps/rollback
  • Cost drivers, in order: function invocation and duration, edge middleware running on every request including assets, image optimisation on uncontrolled sources, and bandwidth.
    • Scope middleware.ts with a tight matcher — an unscoped middleware runs on every asset request and is frequently the largest single line item.
    • Restrict next/image remotePatterns to domains you control; an open configuration is an open image-optimisation proxy.
    • Set spend limits and usage alerts.
ts
// middleware.ts — an unscoped matcher runs on every asset request.
// This one runs on pages only, and is frequently a 10× cost difference.
export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico|.*\\.(?:png|jpg|svg|woff2)$).*)"],
};

#Anti-patterns

Anti-patternWhy it failsFix
Secret in NEXT_PUBLIC_*Inlined into client JavaScriptServer-only variable
Expecting a public variable change to applyBaked at build timeRedeploy
Preview using production credentialsAny pull request writes to productionPer-environment variables
Database client per requestConnection exhaustion under loadModule-scope client + pooler
No connection poolermax_connections hit in secondsTransaction-mode pooler
Migrations through the poolerFails or corruptsDIRECT_URL
In-memory cache or rate limiterPer-instance; resets constantlyShared store
Work after the response returnsInstance frozen; work lostwaitUntil or a queue
Long-running request handlerExecution limit exceededBackground job
Writing to the filesystemRead-only and ephemeralObject storage
Edge runtime with a database driverNo TCP supportNode runtime
Functions far from the databaseRound-trip cost per queryCo-locate regions
Runtime not declaredDefaults change; surprisesDeclare it explicitly
Personalised route rendered staticallyOne user's data served to allCheck the build output
Caching authenticated responsesCross-user data exposureno-store
Unscoped middleware matcherRuns on every asset; dominates costTight matcher
Open remotePatternsFree image proxy for anyoneRestrict to your domains
Unprotected previews with real dataPublicly reachableDeployment Protection
No spend limitsCost discovered on the invoiceLimits and alerts

#Checklist

  • Verify: No secret is exposed through a NEXT_PUBLIC_ variable
  • Verify: Build-time inlining of public variables is understood; changes trigger redeploys
  • Verify: Environment variables are scoped per environment
  • Verify: Preview deployments use non-production credentials and data
  • Verify: Environment variables are validated at startup
  • Verify: One module-scope database client behind a transaction-mode pooler
  • Verify: Migrations use a direct, unpooled connection
  • Verify: No in-memory cache, rate limiter or session state is relied upon
  • Verify: Post-response work uses waitUntil or a queue
  • Verify: Long-running work runs as a background job
  • Verify: Nothing writes to the filesystem outside /tmp
  • Verify: Runtime (nodejs/edge) is declared per route
  • Verify: Functions are co-located with the database region
  • Verify: next build output is reviewed; no personalised route is static
  • Verify: Authenticated responses set no-store
  • Verify: Mutations trigger revalidation
  • Verify: middleware.ts has a tight matcher
  • Verify: next/image remotePatterns are restricted to controlled domains
  • Verify: Preview deployments are protected
  • Verify: Spend limits and usage alerts are configured