For the complete Netlify documentation index, see llms.txt. Markdown versions of any documentation page are available by appending .md to its URL. This page documents the entry file of a server, how to configure it, the request context, and the @netlify/server module. For how instances start and stop, refer to Lifecycle.
Entry file
Section titled “Entry file”A server is defined in a single file at netlify/server/index.ts (or .mts, .js, .mjs). A project can have one server, so the build fails if this directory contains more than one of these files.
Netlify loads your entry file once per instance. When an instance starts, Netlify:
- Sets the
PORTenvironment variableenvironment variableNamed values stored outside your code that your site can read at build time or runtime. to a free port, unless you set it yourself. - Imports the entry file, which runs its top-level code. If that code uses top-level
await, Netlify waits for it. - Runs your start hooks, if you registered any.
- Looks at the entry file's default export, and uses the first row of the following table that matches:
| Default export | How Netlify runs it | WebSockets |
|---|---|---|
A Node.js http.Server that doesn't call listen() | Sends requests to that server | Through the server's upgrade event, so libraries such as ws or Socket.IO work as usual |
An object with a fetch method, as defined by the Fetchable specification, such as a Hono app | Calls fetch(request, context) for each request | With upgradeWebSocket |
An Express or Connect app (a function with handle and use methods), or any function that takes three or more parameters, such as (req, res, next) | Hosts it as a Node.js request listener in its own HTTP server | Not supported, answered with a 501 |
| Any other function | Calls it as a handler, (request, context) => response | With upgradeWebSocket |
| Anything else, or no default export | Waits for your code to start an HTTP server, then sends requests to it | Through the server's upgrade event |
The instance receives no traffic until all these steps have finished. If any step throws an error or exception, the instance fails to start.
For examples, refer to Handler, Your app has a fetch method, Your app is a request listener, and Your framework starts its own server.
Whatever your entry file exports, your code can read the request's context with getContext(), and the entry file can export a config object.
A few things to know:
- A function with two parameters,
(req, res), looks the same as a handler, so it's called as one. To run it as a Node.js request listener, wrap it in a server, as described in Your app is a request listener. - A server your code starts itself must start listening within 10 seconds of your start hooks finishing. Listening on
process.env.PORTis the most reliable option, but it can listen on any port that isn't reserved. If your code starts more than one server, Netlify uses the one listening onprocess.env.PORT, and the instance fails to start if none of them is. - Only Node.js HTTP servers are supported, such as ones created with
node:httpor by a framework. Other kinds of servers, such as a raw TCP server, aren't.
Handler
Section titled “Handler”A handler is a function that takes a Request and a Context, and returns a Response or a promise that resolves to one. It's the same signature as Netlify Functions and Netlify Edge Functions.
import type { Context } from "@netlify/server";
export default async (req: Request, context: Context) => { return new Response(`Hello from ${context.geo.city ?? "somewhere"}!`);};Config object
Section titled “Config object”The Config object configures how a server is deployed and which requests it receives. Export it from your entry file as a config constant, or place it inside the config property of a default export that's a Fetchable. You can also set the same properties in the [server] section of netlify.toml.
For descriptions of each setting with full examples, refer to Configuration.
import type { Config } from "@netlify/server";
export default async () => new Response("Hello, world");
export const config: Config = { region: "fra", size: "medium",};The build fails if the configuration contains a property that isn't listed below, or a value that isn't valid.
excludedPath
Section titled “excludedPath”One or more URL paths that the server doesn't handle. Refer to Excluded paths.
includedFiles
Section titled “includedFiles”An array of glob patterns for additional files to include in the server's bundle. Refer to Included files.
One or more URL paths that the server handles. Defaults to /*. Refer to Paths.
region
Section titled “region”The airport code of the region the server runs in, cmh or fra. Defaults to cmh. Refer to Region.
How many instances the server runs, as an object with min and max. min defaults to 0, and max to the highest your plan allows. Refer to Scale.
The size of the instances the server runs on, small, medium, or large. Defaults to small. Refer to Instance size.
Context
Section titled “Context”The Context object holds information about the request being handled. A handler or a Fetchable receives it as its second argument; any other code can read it with getContext().
It has the following properties.
account
Section titled “account”An object with the id of the team the site belongs to.
cookies
Section titled “cookies”An interface for reading and setting cookies, which works whatever your entry file exports:
cookies.get(name)reads a cookie from the incoming request.cookies.set(options)sets a cookie on the outgoing response, using the same options asCookieStore.set.cookies.delete(name)orcookies.delete(options)tells the client to delete a cookie, followingCookieStore.delete.
deploy
Section titled “deploy”An object with information about the deploy the server belongs to:
branch: the Git branch the deploy was built from.context: the deploy context, such asproductionordeploy-preview.id: the deploy's unique ID.published: whether the deploy is the site's published deploy.skewProtectionToken: a token that identifies the deploy in HTTP requests when skew protection is enabled.
An object with the visitor's geolocation:
city: the name of the city.country: an object with the country's ISO 3166codeand itsname.latitudeandlongitude: the coordinates of the location.postalCode: the postal code, in the format of the visitor's region.subdivision: an object with the ISO 3166codeof the country subdivision and itsname.timezone: the timezone of the location.
The visitor's IP address. In an app built with a framework or a Node.js server, req.socket.remoteAddress and the helpers built on it, such as Express's req.ip, report the same address.
requestId
Section titled “requestId”The Netlify request ID, such as 01FDWR77JMF2DA1CHF5YA6H07C. Netlify adds it to anything your code logs with console while handling the request.
server
Section titled “server”An object with the region the server runs in, as the airport code its configuration names, such as cmh.
An object with information about the site:
id: the site's unique ID.name: the site's name, which is also its Netlify subdomainsubdomainA prefix added to a domain name, such as blog in blog.yoursite.com..url: the site's main address, either its Netlify subdomain or its custom domaindomainThe web address people use to visit your site, such as yoursite.com..
The URL of the request, as a URL object.
The Netlify user who logged in to view the site, when it's a private project or uses team login protection, or undefined otherwise. An object with the following properties:
id: the user's Netlify user ID.email: the email address on the user's Netlify account, if available.expiresAt: when the user's access to the site expires, as aDate.
waitUntil
Section titled “waitUntil”A function that keeps the instance running until a promise settles, for work that should carry on after you respond. Refer to Background work.
@netlify/server
Section titled “@netlify/server”@netlify/server provides the types and helpers for building a server. It's also what gives your code access to the lifecycle hooks, which let you run code when an instance starts (onStart) and when it shuts down (onShutdown), and report how busy it is (onHealthCheck).
Here's how to install it:
npm install @netlify/servergetContext
Section titled “getContext”Returns the Context object of the request being handled. It works anywhere in the code that runs for a request, such as a framework's route handler or middleware, so it's the way to access the context in an app built with a framework.
import { getContext } from "@netlify/server";
app.get("/", (req, res) => { const { geo } = getContext();
res.send(`Hello from ${geo.country?.name ?? "somewhere"}!`);});Return value
Section titled “Return value”The Context object of the current request.
Throws when called outside a request, for example at the top level of the entry file or in a lifecycle hook.
onStart
Section titled “onStart”Registers a hook that runs when an instance starts, after the entry file has loaded and before the instance receives any traffic. If the hook returns a promise, the instance waits for it, and fails to start if it rejects.
This is useful for work that should run once the whole app has been set up, such as connecting to a database, or for libraries that need to prepare something before the server takes traffic.
Start hooks can use Netlify Database, Netlify Blobs, the AI Gateway, and your environment variables, the same as a request can. Keep them short, since the instance receives no traffic until they finish, and an instance that takes too long to start fails to start.
import express from "express";import { onStart } from "@netlify/server";
const app = express();
onStart(async () => { await db.connect();});
app.listen(process.env.PORT);Netlify sends no traffic to your server until your start hooks have finished, even if it's already listening.
Parameters
Section titled “Parameters”hook: a function that returns nothing or a promise. Hooks run one at a time, in the order you registered them.
Call onStart while the entry file loads. Calling it after the instance has started throws an error, since the hook would never run.
onShutdown
Section titled “onShutdown”Registers a hook that runs as soon as an instance starts shutting down, when it stops receiving new traffic. Requests, WebSocket connections, and background work already in progress keep running, so use the hook to explicitly stop work that would otherwise keep running, such as a job queue or open WebSocket connections.
To wait for the work in progress before closing a resource it may still be using, such as a database pool, await drained:
import { onShutdown } from "@netlify/server";
onShutdown(async ({ drained }) => { queue.stop();
await drained; await pool.end();});Refer to Shutdown for how long each step can take.
Parameters
Section titled “Parameters”hook: a function that receives an object with the following property, and returns nothing or a promise. Hooks run in parallel, so one that awaitsdraineddoesn't hold back the others. A hook that throws is logged, and the others keep running.drained: a promise that resolves once the requests, WebSocket connections, and background work in progress have all finished, or once Netlify stops waiting for them. It never rejects.
onHealthCheck
Section titled “onHealthCheck”Registers a hook that reports how busy your server is, adding the resources only your code knows about, such as a database connection pool or a job queue, to the event loop and memory readings Netlify already takes. Netlify uses these reports to decide which instances receive new requests. Refer to Load-aware routing for how it uses them.
import { onHealthCheck } from "@netlify/server";
onHealthCheck(() => ({ utilization: { db_pool: (pool.totalCount - pool.idleCount) / pool.options.max, }, namedMetrics: { db_pool_waiting: pool.waitingCount, },}));Netlify calls your hook in the background, at most once per interval, and uses its latest result, so a hook can be synchronous or asynchronous. A hook that makes a network call can set a longer interval:
onHealthCheck( async () => { const { waiting } = await queue.getJobCounts("waiting");
return { utilization: { job_queue: Math.min(1, waiting / MAX_QUEUE) } }; }, { interval: 10_000 },);You can register as many hooks as you like, including from libraries.
Parameters
Section titled “Parameters”hook: a function that returns a health report, or nothing, directly or as a promise.options(optional): an object with the following property:interval: how often to call the hook, in milliseconds. Defaults to1000, which is also the minimum.
Health report
Section titled “Health report”Every property is optional:
utilization: an object with one entry per resource, each with how busy it is as a fraction of its capacity, between0and1. The keys are names you choose for your app's own resources, as many as you need, such asdb_poolorjob_queue. Netlify looks at the highest entry across all your hooks and its own readings. The namesevent_loopandmemoryare reserved for Netlify's own readings.applicationUtilization: a number between0and1that replaces the highest entry as the instance's overall figure, for apps whose busiest resource doesn't reflect how much more work they can take. If more than one hook sets it, the highest value is used.namedMetrics: an object of values recorded for observability, such as a queue's length or a latency in milliseconds. Unlikeutilization, they don't affect routing or scaling.
Utilization values outside 0 and 1 are clamped to that range, and entries that aren't numbers are ignored.
The health report is based on ORCA (Open Request Cost Aggregation), the open standard from the CNCF xDS project for backends to report how loaded they are, which gRPC and Envoy also use. utilization, applicationUtilization, and namedMetrics map to ORCA's utilization, application_utilization, and named_metrics fields.
If a hook throws, or returns nothing, it contributes nothing that time, and your instance is never stopped or replaced because of it. Netlify counts hooks that throw and logs their errors.
Keep hooks cheap, since they run for as long as the instance does. Prefer reading values your code already keeps in memory over querying another service each time.
upgradeWebSocket
Section titled “upgradeWebSocket”Upgrades a request to a WebSocket connection. You get back a browser-style WebSocket to talk to the client, and a Response to return from your handler.
import { upgradeWebSocket } from "@netlify/server";
export default async (req: Request) => { if (req.headers.get("upgrade") === "websocket") { const { socket, response } = upgradeWebSocket(req);
socket.onmessage = (event) => { socket.send(`Echo: ${event.data}`); };
return response; }
// The same path can serve regular HTTP requests too. return new Response("Connect with a WebSocket client");};upgradeWebSocket works when your entry file exports a handler or a Fetchable. When it exports a server or starts one, attach a WebSocket library such as ws or Socket.IO to that server instead, as described in Real-time.
Parameters
Section titled “Parameters”request: theRequestyour server received. Throws if the request wasn't received through Netlify Server.options(optional): an object with the following properties:protocol: the subprotocol to accept, which becomes the client'sWebSocket.protocol. Should match one of the protocols the client asked for.idleTimeout: the number of seconds between pings to the client. If the client hasn't answered the previous ping when the next one is due, the connection is closed. Pings are disabled when this isn't set.
Return value
Section titled “Return value”An object with the following properties:
socket: aWebSocketfor the server side of the connection.response: theResponsethat completes the upgrade. Return it from your handler as is.
getWebSockets
Section titled “getWebSockets”Returns the WebSocket connections open on this instance, from every call to upgradeWebSocket. Connections to other instances aren't included, and neither are connections that a library such as ws accepts on your own server.
Use it to send a message to every client connected to the instance, or to close every connection when the instance shuts down. Closing with code 1012 tells clients that the server is restarting, so they can reconnect straight away and reach a new instance.
import { getWebSockets, onShutdown } from "@netlify/server";
onShutdown(() => { for (const socket of getWebSockets()) { socket.close(1012, "Server restarting"); }});Return value
Section titled “Return value”An array with a WebSocket for each open connection.
WebSocket
Section titled “WebSocket”The server side of a WebSocket connection, with the same interface as the browser's WebSocket. It has the send() and close() methods, the readyState, protocol, extensions, bufferedAmount, and binaryType properties, and the open, message, close, and error events, available both through addEventListener() and the on* properties.
You get one from upgradeWebSocket rather than by creating it yourself.
CloseEvent
Section titled “CloseEvent”The event dispatched when a WebSocket connection closes, with the same code, reason, and wasClean properties as the browser's CloseEvent.
The following TypeScript types are available:
Config: the configuration objectContext: the context objectHealthCheckHook: a function you can pass toonHealthCheckHealthCheckOptions: the options ofonHealthCheckHealthReport: what a health check hook returnsLifecycleHook: a function you can pass toonStartServerRegion: the codes of the regions servers run inServerSize: the sizes of the instances servers run onShutdownContext: the object a shutdown hook receivesShutdownHook: a function you can pass toonShutdownUpgradeWebSocketOptions: the options ofupgradeWebSocketWebSocketUpgrade: the return value ofupgradeWebSocket
Did you find this doc useful?
Your feedback helps us improve our docs.