new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Next.js · Guides · all subjects

building/custom-server

32 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Custom server basic setup pattern

A custom Next.js server is set up by importing the next function, calling it with configuration options, preparing the app, and then using the request handler with Node.js HTTP server. The pattern is: import next, create app with next({ dev }), call app.prepare(), then createServer((req, res) => { handle(req, res) }).listen(port).

next() function configuration options

The next() function accepts an object with these options: conf (Object, defaults to {}, same as next.config.js), dev (Boolean, optional, defaults to false, whether to launch in dev mode), dir (String, optional, defaults to '.', location of Next.js project), quiet (Boolean, optional, defaults to false, hide error messages), hostname (String, optional, hostname server runs behind), port (Number, optional, port server runs behind), httpServer (node:http#Server, optional, HTTP Server Next.js runs behind), turbopack (Boolean, optional, enable Turbopack, enabled by default), webpack (Boolean, optional, enable webpack).

When to use a custom server in Next.js

A custom Next.js server should only be used when the integrated router of Next.js cannot meet your application requirements. For most applications, you do not need this approach and should use Next.js's built-in server with next start instead.

Custom server incompatibility with standalone output mode

When using standalone output mode, custom server files are not traced. Standalone mode outputs a separate minimal server.js file instead, and these two approaches cannot be used together.

server.js is not processed by Next.js compiler

The server.js file does not run through the Next.js Compiler or bundling process. The syntax and source code in this file must be compatible with the current Node.js version being used.

Custom server package.json scripts setup

To run a custom server, update package.json scripts: set dev to "node server.js", build to "next build", and start to "NODE_ENV=production node server.js".

Load scripts in layout for multiple routes

To load a third-party script for multiple routes, import Script from 'next/script' and include the Script component directly in your layout component. The script will be fetched when the layout route or any nested route is accessed, and Next.js ensures the script loads only once even if users navigate between multiple routes in the same layout.

Load scripts for all routes in root layout

To load a third-party script for all routes in the application, import Script from 'next/script' and include the Script component in your root layout file (app/layout.tsx or pages/_app.js). The script loads and executes when any route is accessed, and Next.js ensures it only loads once even during navigation.

Script loading strategy options

The Script component supports four loading strategies via the 'strategy' property: beforeInteractive (load before Next.js code and page hydration), afterInteractive (default - load early but after some hydration), lazyOnload (load during browser idle time), and worker (experimental - load in a web worker).

Worker strategy for script offloading (experimental)

Scripts using the 'worker' strategy are offloaded and executed in a web worker using Partytown to improve performance by dedicating the main thread to application code. This strategy is experimental and only works with the nextScriptWorkers flag enabled in next.config.js. Enable it by setting experimental.nextScriptWorkers to true.

Setup web worker scripts with Partytown

After enabling nextScriptWorkers in next.config.js, run the development server (npm run dev, pnpm dev, yarn dev, or bun dev). Next.js will guide installation of required packages and show instructions to install Partytown. Once setup is complete, using strategy='worker' automatically instantiates Partytown and offloads the script to a web worker.

Inline scripts with Script component

Inline scripts not loaded from external files are supported by the Script component. They can be written by placing JavaScript within curly braces or using the dangerouslySetInnerHTML property. An 'id' property must be assigned to inline scripts for Next.js to track and optimize them.

Script event handlers

The Script component supports event handlers to execute code after certain events: onLoad (execute after script finishes loading), onReady (execute after script loads and every time component mounts), and onError (execute if script fails to load). These handlers only work when next/script is imported and used inside a Client Component with 'use client' defined.

Additional DOM attributes on Script component

Many DOM attributes can be assigned to the Script element that are not directly used by the component itself, such as 'nonce' or custom data attributes. Any additional attributes are automatically forwarded to the final, optimized script element in the HTML.

Partytown configuration in Pages Router

In the Pages Router, custom Partytown configuration can be added in a custom _document.js file using a script element with the data-partytown-config attribute inside the Head component. The configuration object must include lib: '/_next/static/~partytown/' to tell Partytown where Next.js stores library files. If using an asset prefix, include it in the lib path. See Partytown's configuration options documentation for available properties.

Inline script example with document manipulation

Example of an inline script that removes a hidden class from a banner element: <Script id="show-banner">{`document.getElementById('banner').classList.remove('hidden')`}</Script>. The id property is required for inline scripts.

Layout script example

Example of loading a script in a layout that applies to multiple routes: ```tsx import Script from 'next/script' export default function DashboardLayout({ children }) { return ( <> <section>{children}</section> <Script src="https://example.com/script.js" /> </> ) } ```

Root layout script example

Example of loading a script for all routes in the root layout: ```tsx import Script from 'next/script' export default function RootLayout({ children }) { return ( <html lang="en"> <body>{children}</body> <Script src="https://example.com/script.js" /> </html> ) } ```

Script event handler example

Example of using onLoad event handler with Script component: ```tsx 'use client' import Script from 'next/script' export default function Page() { return ( <> <Script src="https://example.com/script.js" onLoad={() => { console.log('Script has loaded') }} /> </> ) } ``` This requires 'use client' directive in an App Router component.

Script with custom attributes example

Example of Script component with additional DOM attributes: ```tsx import Script from 'next/script' export default function Page() { return ( <> <Script src="https://example.com/script.js" id="example-script" nonce="XUENAJFW" data-test="script" /> </> ) } ``` Additional attributes like nonce and data attributes are automatically forwarded to the final script element.

Recommendation for third-party script placement

Include third-party scripts in specific pages or layouts rather than globally to minimize unnecessary impact to application performance.

Worker strategy not yet stable for App Router

The 'worker' strategy for offloading scripts to web workers is not yet stable and does not work with the App Router. Use with caution.

Reverse proxy recommended for self-hosted Next.js

When self-hosting Next.js, it is recommended to use a reverse proxy like nginx in front of the Next.js server rather than exposing it directly to the internet. A reverse proxy can handle malformed requests, slow connection attacks, payload size limits, rate limiting, and other security concerns, offloading these tasks from the Next.js server. This allows the server to dedicate its resources to rendering rather than request validation.

Image Optimization with self-hosted Next.js

Image Optimization through next/image works with self-hosted Next.js with zero configuration when deploying using next start. Images are optimized at runtime, not during the build. For static exports, you can define a custom image loader in next.config.js. On glibc-based Linux systems, Image Optimization may require additional configuration to prevent excessive memory usage.

Proxy works with self-hosted next start only

Proxy works with self-hosted Next.js with zero configuration when deploying using next start. However, it is not supported when using a static export because it requires access to the incoming request.

Runtime environment variables in App Router

In the App Router, you can safely read environment variables on the server during dynamic rendering. By default, environment variables are only available on the server. To expose an environment variable to the browser, it must be prefixed with NEXT_PUBLIC_, but these will be inlined into the JavaScript bundle during next build. Using the connection() function from next/server will opt into dynamic rendering, making the environment variable evaluated at runtime rather than build time.

assetPrefix configuration for static assets

If you want to host static assets on a different domain or CDN, you can use the assetPrefix configuration in next.config.js. Next.js will use this asset prefix when retrieving JavaScript or CSS files. Separating your assets to a different domain does come with the downside of extra time spent on DNS and TLS resolution.

Server Function encryption key for multiple instances

Next.js encrypts Server Function closure variables before sending them to the client. By default, a unique encryption key is generated for each build. When running multiple server instances, all instances must use the same encryption key. Otherwise, a Server Function encrypted by one instance cannot be decrypted by another, causing 'Failed to find Server Action' errors. Set a consistent encryption key using the NEXT_SERVER_ACTIONS_ENCRYPTION_KEY environment variable. The key must be a base64-encoded value with a valid AES key length (16, 24, or 32 bytes). Next.js generates 32-byte keys by default.

deploymentId configuration for version skew protection

Configure a deploymentId to enable version skew protection during rolling deployments. This ensures clients always receive assets from a consistent deployment version. When configured, static assets include a '?dpl=<deploymentId>' query parameter and client-side navigation requests include an 'x-deployment-id' header. If a mismatch is detected, Next.js triggers a hard navigation (full page reload) instead of a client-side navigation.

deploymentId configuration example

Example configuration in next.config.js: ```js module.exports = { deploymentId: process.env.DEPLOYMENT_VERSION, } ```

Version skew problems in rolling deployments

When self-hosting across multiple instances or doing rolling deployments, version skew can cause: missing assets (client requests JavaScript or CSS files that no longer exist on the server), Server Function mismatches (client invokes a Server Function using an ID from a previous build that the server no longer recognizes), and navigation failures (prefetched page data from an old deployment is incompatible with the new server).

after function fully supported when self-hosting

The after function is fully supported when self-hosting with next start. When stopping the server, ensure a graceful shutdown by sending SIGINT or SIGTERM signals and waiting. The Next.js server will finish in-flight requests and execute any pending after() callbacks before exiting. Platforms should allow a configurable drain period of 10-30 seconds to ensure all background work completes.

Give your agent this brain