8 min read
What a production Next.js and Vercel setup includes, and what to expect from a Next.js development agency
A Next.js site that renders correctly is not yet a production setup. Environments, secrets, caching, middleware, third-party scripts, background work and monitoring are what separate the two.
A production Next.js and Vercel setup includes separate preview and production environments, server-only secrets, a deliberate rendering and caching strategy, rules for images and third-party scripts, background work that is not lost, and monitoring. When you hire a Next.js development agency, ask for these as deliverables, not only pages that look right.
This guide describes what production means for a Next.js App Router project on Vercel. It uses this portal, which runs on that stack, as a source of implementation-level observations. It is not a benchmark and makes no claims about speed or conversion; it is a list of what to build and what to check.
Why a working Next.js site is not yet a production setup
Next.js makes it easy to get something on screen, and Vercel makes it easy to deploy it. Those strengths hide how many decisions remain. Which pages are rendered on each request and which are cached? Where do secrets live, and can any of them reach the browser? What happens to a background task when the response has already been sent? Who notices when a scheduled job stops running?
A project can answer none of these and still look finished in a demo. The gaps appear under real traffic, during a security review, or on the day an integration fails silently and nobody can tell for how long.
What teams often get wrong
- Treating preview deployments as optional, so changes are first tested in production.
- Prefixing configuration for the browser without realizing it is now public, or reading secrets in code that runs on the client.
- Leaving caching to defaults, then being surprised by stale pages or by every request hitting the database.
- Starting background work after a response and assuming it will finish.
- Letting middleware run on every path, including analytics proxies, static assets and API routes that should bypass it.
- Adding third-party scripts and widgets in ways that fight React hydration.
What a production setup includes
Environments and previews
Every branch or pull request gets a preview deployment with its own configuration, and production configuration is only used in production. Preview environments should point at non-production data and services wherever possible, so reviewing a change cannot send real email or charge real cards.
Secrets and configuration
Server secrets are available only to server code and never to client bundles. Configuration intended for the browser is treated as public by design. For teams with several services, a single source of truth for secrets, such as a cloud secret manager mirrored into the hosting provider as sensitive values, avoids copies drifting apart. Files that must never be uploaded, such as service account keys and local environment files, are excluded from deployments explicitly.
Rendering and caching
Each route has an intentional strategy: static, revalidated on a schedule or on demand, or rendered per request. Data fetches have explicit cache behavior. Content managed in a CMS or database is cached with a known freshness window, and there is a way to refresh it when an editor publishes.
Middleware and routing
Middleware handles cross-cutting concerns such as locale routing, redirects and access checks, with a matcher that excludes paths it should not touch. Redirects and canonical URLs are defined so that each page has one address. Sitemaps and robots rules reflect what should actually be indexed.
Images, fonts and third-party scripts
Remote image hosts are allowlisted explicitly for the image optimizer. Fonts are loaded through the framework so they do not block rendering. Analytics, ads and widgets are injected in a way that does not produce hydration mismatches, usually after mount on the client.
Background work and scheduled jobs
Work that happens after a response uses the framework's post-response mechanism rather than an unawaited promise. Work that must not be lost uses a durable queue or an outbox with retries. Scheduled jobs are declared in project configuration, authenticated, and monitored.
Metadata, structured data and languages
Every indexable page has a title, description, canonical URL and social preview image generated from its content. Structured data describes the organization, services, articles and FAQs where it is accurate to do so. If the site serves several languages, each localized page declares its alternates so search engines show the right version, and right-to-left languages get correct document direction rather than mirrored styles added by hand.
Forms, leads and integrations
Contact and inquiry forms save the primary record before calling optional services such as email, CRM or analytics, and report each outcome separately. The article on connecting website content to CRM inquiries describes that pattern in detail, including why a post-response task is not a durable queue.
Observability
Runtime errors, function logs, web vitals and uptime are visible to someone who will act on them. Errors shown to visitors are safe and specific, while details go to logs.
Implementation considerations
Pin the runtime and package manager. Declare the Node.js version and the install and build commands so local, preview and production builds behave the same way.
Watch server bundle boundaries. Some server libraries, particularly those that use native modules or gRPC, work better when excluded from bundling and loaded as external packages at runtime. The symptom of getting this wrong is a build that passes and a function that fails.
Know your function limits. Serverless and fluid compute functions have execution time and memory limits that depend on the plan and configuration. Long AI calls, file processing and large exports may need streaming, background processing or a different service.
Design API routes for failure. Validate input, return clear status codes, keep the primary operation separate from optional integrations, and record the outcome of each integration separately so a failed email does not look like a failed submission.
Trade-offs
Aggressive caching reduces cost and latency but makes freshness harder to reason about. Per-request rendering is simpler to reason about but costs more and depends on backend speed. Most real projects mix both, and the important thing is that the mix is deliberate and documented.
Vercel removes a great deal of infrastructure work: builds, previews, global delivery and scaling. In exchange you accept its execution model and pricing structure. For long-running jobs, heavy background processing or unusual networking needs, a separate worker or service alongside the Next.js app is often cleaner than forcing everything into functions.
Centralizing secrets in a cloud secret manager adds a dependency and a little setup, but it removes the most common source of configuration drift between environments and team members.
Lessons from this portal
These are code-level observations from the ImadDhin portal, a Next.js App Router app on Vercel with Firebase. They describe the implementation, not traffic or revenue.
- The project declares its install and build commands and its Node.js version, so every environment builds the same way, and it declares scheduled jobs, such as a weekly performance check, in project configuration rather than relying on an external scheduler.
- A deployment ignore file explicitly excludes credential files and local environment files from command-line uploads, and credential files are better kept outside the project directory altogether. It is easy to forget until a key ends up in a deployment artifact.
- Server secrets live in a cloud secret manager and are mirrored into Vercel as sensitive values. Server code reads the environment first and falls back to the secret manager, so a missing mirror degrades gracefully instead of breaking a route.
- Google Cloud client libraries that rely on gRPC are marked as external server packages, so they load from dependencies at runtime instead of being bundled into the function. Libraries of this kind are a common source of failures that a successful build does not reveal.
- The internationalization middleware has to skip the analytics reverse-proxy path. Without that exclusion, session replay and feature flag traffic is treated as a page request and redirected.
- Third-party review widgets are mounted on the client after render through empty host elements. Server-rendering their markup produced hydration errors and invalid nested links.
- Remote image hosts used by content must be allowlisted, or the image optimizer errors at runtime for pages that worked in development with local images.
- Post-response work for CRM synchronization uses the framework mechanism, which improves request lifecycle handling, but it is not a durable queue. Guaranteed delivery would need persisted job state.
Common mistakes to test for
- Search the client bundle for anything that looks like a secret or private endpoint; the guide to moving secrets out of the client bundle covers where they usually hide.
- Open a preview deployment and confirm it uses non-production services.
- Publish a CMS change and confirm the page updates within the expected window.
- Request an analytics proxy path, a static asset and an API route, and confirm middleware does not rewrite them.
- Load pages with third-party widgets and check the console for hydration warnings.
- Break an optional integration deliberately and confirm the primary action still succeeds and the failure is logged.
- Disable a scheduled job and confirm someone would notice.
When a simpler solution is better
A marketing site with a handful of pages and a contact form does not need a secret manager, a durable queue or a detailed caching policy. Static pages, a form handler and basic analytics may be all it needs, and adding more is cost without benefit.
Likewise, if a product is still a prototype for a small group of testers, focus on secrets and environments first and postpone the rest. The full setup earns its keep when real users, real money or real data are involved.
Ask for a production setup, not just pages
Use the sections above as a checklist when you evaluate a Next.js development agency or review your own project. You can read how ImadDhin works with Next.js and Vercel, see prototype-to-production rescue if your app was generated by an AI builder, review how engagements are structured, or book a 30-minute call to walk through your current setup and what it is missing.
Frequently asked questions
What should a Next.js development agency deliver besides the website?
Preview and production environments, server-only secrets, a documented rendering and caching strategy, middleware with correct exclusions, image and script rules, reliable background work, monitoring, and a repeatable build with pinned runtime versions.
Can environment variables leak to the browser in Next.js?
Yes. Values explicitly exposed to the browser are bundled into client code and are public. Secrets must only be read in server code, and the client bundle should be checked for anything sensitive.
Is it safe to run background work after sending a response on Vercel?
Use the framework's post-response mechanism rather than an unawaited promise. For work that must not be lost, such as CRM sync or payments follow-up, use a durable queue or outbox with retries.
When does a Next.js app need something besides Vercel functions?
When jobs run longer than function limits allow, need heavy processing, or require persistent connections. A separate worker or service alongside the Next.js app is often simpler than forcing that work into functions.
Why does my Next.js middleware break analytics or API routes?
Usually because its matcher includes paths it should skip. Exclude analytics proxies, static assets and API routes that do not need locale or auth handling.
Make your Next.js app production-ready
App Router, AI surfaces and production deployment.
Next.js and Vercel practiceReview your current setup and what it is missing.
Book a 30-minute callHarden apps generated with Lovable, Bolt, v0 or Cursor.
Rescue an AI-built appKeep reading
Secrets in AI-generated apps: moving keys out of the client bundle
AI app builders often wire provider keys straight into browser code. Here is how to classify credentials, move secret-bearing calls server-side, rotate what shipped and stop it from coming back.
How to turn a Lovable/v0 prototype into a production application
AI builders ship demos fast. Production needs auth, payments, secrets hygiene, observability, and an architecture that survives real users — here is the hardening path I use.
Firebase vs Supabase for AI products
Firebase is strongest for mobile-first products that need realtime sync, push and a managed Google ecosystem. Supabase is strongest when your AI features lean on relational data, SQL and vector search in Postgres. Here is how to choose by workload.