Next.js
Deploy a Next.js app with its server features intact.
Next.js is the framework Nitroship supports natively (managed). With no adapter to configure, static pages, prerendering and ISR, server routes, API routes, middleware, and image optimization all work. You do not need output: 'standalone' either.
Requirements
- Next.js 16.2 or later.
package.jsonat the deployment root must depend onnext; the remote builder installs dependencies and then checks the version actually installed. - A compute region. This is where your server runs. There is no default, so pick one under Configuration below.
Deploy
Install the CLI
curl -fsSL https://nitroship.co/install.sh | bash
ntro loginAlready installed? Skip ahead. Full options, PATH setup, and updates: Install the CLI.
ntro apps create my-next-app
ntro deploy . --prodThe remote builder installs dependencies, runs next build, and deploys static files and server code separately. To build on your own machine instead, install dependencies first and add --local:
ntro deploy . --prod --localWhen it finishes, open a static page and a server route at the URL the CLI printed. The repository's examples/hello-next has SSG, SSR, ISR, and API route examples in one app.
Configuration
Set the server region and size in whichever place you prefer:
- App Settings > Compute in the console
nitroship.jsonat the deployment root
{
"compute": {
"regions": ["kr-icn"],
"tier": "standard"
}
}When both are set, nitroship.json wins field by field. For example, if the file sets only regions, the region comes from the file and the tier from the console. All fields and defaults are listed under CLI configuration > Compute settings.
To change the build command, use build.command. build.outputDirectory is ignored for Next.js.
Changed a console setting and nothing happened?
Settings are locked in when a build starts, so existing deployments do not pick them up. Deploy again, or press Apply now in the console, which redeploys current production with the new settings without rebuilding. See Managing deployments.
Public SSR response caching
For public dynamic routes, set CDN-Cache-Control with next.config's headers() or middleware rather than relying on Next.js's generated Cache-Control. The optional Edge response cache is separate from prerender/ISR and requires operator enablement. Do not cache personalized responses; Set-Cookie, private in the chosen policy, and Vary: Cookie prevent storage. See Cache invalidation for header precedence, limits, tags, and invalidate versus delete. The repository's examples/hello-ssr-cache demonstrates render timestamps and host-specific cached output.
The Edge forwards these evaluated configuration headers to compute even though Next.js runs in minimal mode. A function's policy header replaces the configured value for the same header name; Vary and cache tags are combined instead. A configured Vary: Cookie therefore still prevents caching when Next.js adds its own Vary fields. The 128-tag limit applies to the combined tags. The selected configuration headers have an 8 KiB encoded transport limit; oversized configuration is ignored and logged, so do not rely on it to define a cache policy.
Good to know
- Images: the default Next.js image loader configuration is picked up automatically. Tune image options only in
next.config; do not add animagesblock tonitroship.json. - Locale domains:
i18n.domains(one domain per language) is not supported. Use locale paths such as/koand/en.
Advanced: readiness checks and warm-up
You can skip this in everyday use. Read it if your app does work at startup or you want to tune cold starts.
Background: seed snapshots
To start new instances quickly when traffic grows, Nitroship boots your app once, saves that running state as a snapshot (seed), and restores from it. A warm-up request renders your home page once before the snapshot.
The health check confirms the app can take requests. It runs on a fresh start (cold start), when creating a seed, when reviving a paused instance (checkpoint restore), and when a restore fails and the instance starts fresh instead. Restoring an existing seed only quickly checks that the port accepts connections.
Health check: /__nitroship/health
Newly built Next.js apps get a /__nitroship/health route added by Nitroship, and the health check uses it. Nothing to configure.
- It returns
503until the Next.js server is prepared (NextServer.prepare()) and route preloading has finished, then200. Both responses have an empty body. - Preloading only
imports each route file. It does not render pages or run route handlers or middleware.
Module top-level code runs before the snapshot
Because route files are imported, code at the top of a file (for example, creating a database connection) runs before the snapshot is taken. Right before the snapshot, Nitroship waits for open network connections to go quiet, and connections opened this way count too. Preloading is also best effort: routes that fail to import are skipped, so a 200 does not guarantee every route loaded.
Turn preloading off: for comparison or troubleshooting, set the environment variable NITROSHIP_NEXT_PRELOAD=0 and deploy again. The health check then waits only for prepare(). 1 or no value keeps it on.
Use your own endpoint: to check a route of your own, set it in nitroship.json. You must implement that route yourself; /__nitroship/health stays reserved after the change.
{"compute": {"healthPath": "/api/healthz"}}Whichever path is used, the health check sends it a GET request:
2xx,3xx, and404responses count as ready.- Each attempt waits up to 2 seconds for response headers and is retried until it passes. The overall limit is 30 seconds.
Warm-up request: GET /
When creating a seed snapshot, Nitroship sends a single GET / request to your app right after the health check passes. This runs your home page's rendering code once ahead of time. Nitroship reads the whole response before taking the snapshot.
- The request carries
User-Agent: nitroship-seed-warmupandx-nitroship-warmup: 1. - Unlike the health check, it really renders the page and runs middleware. If that code has side effects, such as recording analytics, filter this request out using the headers above.
- It is best effort within a time limit; errors or timeouts never fail the deployment.
- It is not sent on snapshot restore or for real visitor requests. Changing
compute.healthPathdoes not change the warm-up path; it stays/.
Existing deployments are not affected
The health path and warm-up are recorded in the deployment at build time. Deployments built before these features keep their original health path (usually /) and get no warm-up. Redeploy, Apply now, promote, and rollback all keep the recorded values, so you need to rebuild to get the new behavior. Apps other than Next.js never receive the warm-up request.
Related guides
Image optimization · Cache invalidation · Environment variables · Migrate from Vercel