Engineering

How to Configure Nitro for Fast, Scalable Vue Apps

You searched for “nuxt nitro” because you want real configuration examples. This post walks through practical Nitro settings for cold starts, prescaling and deployment, with tradeoffs spelled out.

Sep 14, 2026· 9 min read· Stack Innovations
Abstract layered composition suggesting web infrastructure and routing.
Nuxt Nitro sits between your Vue app and your hosting platform, and its configuration shapes how requests actually flow.

You searched for “nuxt nitro” because you want real configuration examples. This post walks through practical Nitro settings for cold starts, prescaling and deployment, with tradeoffs spelled out.

Your Nuxt app works locally. In production, the first request to a content route is slow, the API feels uneven under load, and changing the hosting preset seems to improve one metric while damaging another.

That’s a normal Nitro problem.

Nitro sits between your Nuxt application and its hosting environment. It builds the server output, selects a runtime target, handles server routes, applies caching rules and adapts the result for a platform such as a Node host, serverless provider or edge runtime. The configuration only helps if it matches how requests will actually run.

What Nuxt Nitro actually does for your app

A Nuxt build has two useful parts. The client bundle runs in the browser. The Nitro server build runs on the host and handles SSR, server routes, middleware and other server-side work.

Nitro’s build process creates output for a chosen deployment preset. The preset determines how that output starts and how it receives requests. The same application can produce a long-running Node server, a clustered Node process or an edge-oriented function, depending on the target described in the Nitro configuration documentation.

That split matters for startup time.

A long-running Node process can load modules once and reuse connections across requests. A serverless or edge function may need to initialise its runtime before handling a request. That initialisation is the cold start. The cost comes from the runtime, imported modules, connection setup and application work performed before the handler can respond.

Not every slow request is a Nitro issue. A database query, an oversized browser bundle or a distant origin can dominate TTFB even when Nitro starts quickly. Use Why your stack feels slow before you touch Nitro as a broader checklist before changing server configuration.

The preset is not a performance switch. It is a contract between the build and the host.

Choosing the right Nitro preset for your hosting model

Start with the host, not with the fastest-sounding preset.

For a conventional VM or container, node-server is usually the clearest starting point. It produces a Node server that stays alive while the host keeps it running. That supports module reuse, connection pooling and predictable concurrency. You still need process supervision, health checks and a plan for horizontal scaling.

node-cluster is aimed at running multiple Node workers on one machine. Each worker has its own event loop and memory space. This can improve throughput when the machine has spare CPU cores, but it also increases memory use and makes coordination more complicated. A cache or session stored only in process memory won't be shared between workers.

Serverless presets fit platforms that create function instances in response to traffic. They can scale out without you managing processes, but each instance has limits on memory, execution time and concurrency. The platform decides when instances are created and removed. Nitro produces the function shape, but it does not remove those platform limits.

Edge presets target runtimes close to users. They can reduce network distance for simple responses, yet they often restrict Node APIs, native modules and long-lived connections. A route that works on node-server may need different dependencies or storage when moved to an edge runtime.

The Nuxt deployment documentation maps Nitro deployment presets to hosting models, including Node, serverless, edge and static output. Treat that mapping as a starting point, then test the actual host. Assess the host's documented runtime limits instead of treating the preset label as a performance guarantee.

Teams weighing static output against hybrid rendering may also benefit from Choosing a Jamstack style architecture around Nuxt. The key decision is where each route should execute, not whether the architecture has a fashionable name.

Abstract representation of clustered server processes and routing paths.
Nitro presets like node-cluster change how many workers handle traffic and how your app scales on a single host.

Configuration patterns to reduce cold-start latency

A cold start is the delay between a platform creating or waking an instance and that instance becoming ready to serve the request. A route-rule cold boot is more specific. It happens when a request reaches a route whose Nitro rule causes additional server or cache work during startup.

The practical fix is to make the first execution small.

Keep edge handlers narrow. Avoid importing a large SDK into a route that only needs a small utility. Move database work behind a service designed for the target runtime. If a route needs native Node modules, do not force it into an edge preset simply because the edge is geographically closer.

A basic Nuxt configuration might look like this:

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/': { prerender: true },
    '/docs/**': { swr: true },
    '/account/**': { ssr: true },
    '/api/catalog': { cache: { maxAge: 60 } }
  }
})

The exact values should follow the content's freshness requirements. The point is to classify routes deliberately. Static routes should not pay for request-time rendering. Content routes can serve a cached response. Private account pages should remain dynamic.

For a serverless or edge deployment, a practical starting point is to keep each handler focused and initialise only the clients it uses. The edge cold-start analysis in this Nitro route-rule performance blueprint shows why route rules and preset choice can affect startup latency rather than only cache behaviour.

For a latency-sensitive application with heavy server dependencies, node-server is often safer. A warm process can retain loaded modules and connection pools. That does not make every response fast. It does remove a class of repeated startup work.

node-cluster can help when one process cannot use the available CPU. It is not a cure for a slow route. If every worker performs the same expensive database query, clustering can increase pressure on the database while making the application appear faster only under a narrow test.

Prescaling and concurrency: node-server vs node-cluster

A single node-server process handles concurrent asynchronous work through Node's event loop. This works well for network-bound SSR and API requests, provided handlers do not block the event loop with CPU-heavy work.

A blocking render, large synchronous transformation or expensive encryption operation affects every request in that process. Adding workers can isolate those event loops. With node-cluster, each worker accepts traffic and processes its own requests. The host or process manager still needs to decide how many workers should run.

A container pattern might use the Nitro node server and let the orchestrator run multiple container replicas. That is different from clustering inside one container. Replicas provide failure isolation and can scale independently. Cluster workers share the machine and usually share its resource limits.

Prescaling belongs to the platform or process manager. Nitro defines the server output and runtime behaviour. Your host decides whether instances stay warm, how many replicas exist and how traffic is distributed. A serverless platform may keep a pool of warm instances, but your application cannot assume that every instance will remain warm.

Watch for three failure modes.

CPU saturation leaves event loops unable to accept work promptly. Long garbage collection pauses appear when workers retain too much memory or create excessive short-lived objects. Noisy neighbours reduce available CPU when several workloads share a host.

Treat worker count as a setting to validate with measurements. Before increasing it, measure event-loop delay, memory per worker, request concurrency and downstream error rates. If the database is already at its connection limit, adding Nitro workers may turn a latency problem into an outage.

Abstract illustration of layered caching and fast request paths.
Nitro caching and route rules let you move expensive work off the hot path so cold starts hurt less.

SSR, caching and routeRules that actually move the needle

Caching works best when you decide what may be stale.

Nitro's Cache API supports cached route handlers, cached functions and storage drivers that can include external systems such as Redis. The Nitro Cache API documentation covers those patterns and the relationship between cached handlers, storage and route rules.

A cached handler can keep expensive server work out of the request path:

// server/api/catalog.get.ts
export default defineCachedEventHandler(async () => {
  return await loadCatalogFromDatabase()
}, {
  maxAge: 60,
  name: 'catalog'
})

Use this for data that can tolerate a short period of staleness. It reduces backend load and usually improves TTFB after the cache is populated. It also creates a failure mode. A bad response can remain available from cache, and invalidation must be understood before content changes are published.

Route rules are useful for broader route groups:

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/products/**': { swr: 300 },
    '/news/**': { isr: true },
    '/checkout/**': { ssr: true },
    '/api/search': { cache: false }
  }
})

The names and supported behaviour depend on the deployment target. Confirm the generated output and platform adapter rather than assuming that every cache mode behaves identically everywhere.

A practical split is static, cached and dynamic. Static pages have no request-time data. Cached pages can be slightly stale. Dynamic routes need current data or user-specific context.

Caching reduces render work and backend traffic. It does not fix a slow cache miss. It can also make errors harder to interpret because one instance may serve an old successful response while another exposes the current failure. Log cache hits, misses and stale responses alongside TTFB.

Tuning builds: externals, rollup and what to bundle

Nitro's build settings control how dependencies are packaged. Rollup can bundle modules into the server output. External dependencies remain separate and are resolved at runtime where the deployment environment supports that behaviour. The available controls are described in the Nitro configuration reference.

Bundling can reduce runtime resolution work and make a serverless function more self-contained. That helps when the deployment system has unreliable module installation or when a small dependency graph is repeatedly loaded during cold starts.

Bundling everything is not automatically better.

A large SDK used by one infrequent route can inflate the function package and increase startup work. Native bindings may fail after bundling or may require platform-specific files that the bundler cannot package correctly. Externalising a dependency can keep the output smaller, but the host must then provide a compatible installed module.

For edge targets, bundle only code supported by the edge runtime. Node built-ins, native database clients and filesystem assumptions are common reasons an edge build fails after deployment. For Node targets, external dependencies can be sensible when the host controls installation and the modules include native components.

Inspect the generated output. Check which routes import large packages. A dependency used on every request deserves different treatment from one used by a single administrative endpoint.

Deployment recipes by platform type

For a traditional Node host or container, start with node-server. Keep the process warm, put a reverse proxy or load balancer in front of it and use an external cache when several replicas need the same data. Add node-cluster only after measuring CPU use and event-loop delay on one process. As part of operating it, check TTFB, memory growth, worker restarts and database connection pressure.

For serverless functions, use the provider's Nitro preset and keep route handlers small. Apply caching to read-heavy endpoints before increasing function memory or instance counts. Avoid creating database connections for routes that do not query the database. Watch cold-start duration, warm-start duration, concurrent executions, function errors and cache miss latency.

For edge runtimes, use an edge preset only when the routes and dependencies fit the runtime. Put static and cacheable content at the edge. Keep personalised or storage-heavy work on a compatible origin when necessary. Watch TTFB by region, cold-boot frequency, cache hit rate and origin wait time.

Test with production-like data. A local development server does not reproduce platform startup, cache storage or connection behaviour.

Next, list every important route and mark it static, cached or dynamic. Then choose the preset that matches the host you can operate. Treat benchmark results as input for testing rather than as a reason to select a preset by its label alone. If the results still conflict, consider a Nuxt development and Nitro performance review to audit the build, hosting setup and request path together.

Questions people actually ask

What is Nitro in Nuxt and why should I care about it for performance?

Nitro is the server engine that runs your Nuxt app in production. It controls how server side rendering, APIs and routing behave in different environments. The preset you choose and the config you apply directly affects startup time, memory use, caching options and where your code can run, so if you ignore Nitro you often end up with avoidable cold starts or scaling problems.

Which Nitro preset should I use for a typical production Nuxt app?

It depends on your host and latency goals. The Nitro configuration docs list presets like node-server or node-cluster for long lived node processes and edge or serverless oriented targets for hosts that spin functions up and down. If you run on a traditional node host or containers, a node preset is usually safer for predictable latency. If your platform is function based or offers edge workers, you need an edge or serverless preset but you also need to plan for cold starts and use Nitro caching to offset them.

How do I reduce Nuxt Nitro cold starts on edge or serverless hosts?

The Nuxt deployment docs and the edge performance blueprint show that two things matter most. Choose a preset that matches your host and test its startup profile. Then, use Nitro routeRules and the Cache API so that expensive work happens rarely, not on every cold start. For example, cache heavy data reads or whole route responses where possible and use stale while revalidate so users see a quick cached response while Nitro refreshes data in the background.

Does Nitro automatically scale my Nuxt app?

Nitro defines how your app can scale across processes or functions, but it does not auto scale on its own. On node hosts, presets like node-cluster help you use multiple workers on one machine, which improves concurrency if the machine has spare CPU. On serverless and edge platforms, scaling is mainly controlled by the provider. Nitro needs to be configured so that each instance starts fast and uses caching and efficient bundling to keep per instance cost and latency down.

Read next

← All posts
The short list

One email when
we publish.

Engineering notes from real builds. No newsletter theatre, no drip sequence, unsubscribe in one click.

We reply to real questions in 1-2 hours. Start a conversation instead →

Follow us on Google See our posts more often in Search and AI Overviews.