Netlify Adapter
The @astrojs/netlify adapter lets you deploy a server-rendered Astro project to Netlify, where your on-demand routes run as Netlify Functions or, optionally, as Edge Functions at the network edge. Astro stays zero-JS-by-default and ships only the islands you opt into with client:*, while the adapter wires up the serverless runtime, request handling, and asset routing for you. This is the path you reach for when static output alone is not enough — you need API routes, server endpoints, on-demand rendering, or middleware running on Netlify’s platform.
Installing the adapter
The fastest way to add the adapter is astro add, which installs the package, updates your config, and sets a sensible output mode.
npx astro add netlify
If you prefer to do it manually, install the package and register it yourself.
npm install @astrojs/netlify
Then set the adapter in astro.config.mjs. The adapter implicitly enables on-demand rendering, so you only need output: 'server' if you want every route rendered on the server by default. Otherwise leave the default static output and mark individual routes with export const prerender = false.
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify';
export default defineConfig({
output: 'server',
adapter: netlify(),
});
Astro 5 uses
output: 'static'by default and renders any route on demand when you setexport const prerender = falsein that page or endpoint. Useoutput: 'server'only when most of the site should be dynamic.
Netlify Functions vs Edge Functions
By default the adapter targets standard Netlify Functions — Node.js serverless functions with full access to the Node runtime, npm packages, and filesystem-style APIs. You can instead run rendering on Netlify Edge Functions, which execute on a Deno-based runtime distributed close to the user for lower latency, at the cost of a more constrained API surface.
Enable the edge runtime with the edgeMiddleware option for middleware, or build edge-rendered routes by configuring the adapter accordingly.
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify';
export default defineConfig({
output: 'server',
adapter: netlify({
edgeMiddleware: true,
}),
});
| Capability | Netlify Functions | Edge Functions |
|---|---|---|
| Runtime | Node.js | Deno (edge) |
| Latency | Regional | Globally distributed |
| Node/npm APIs | Full | Limited (Web APIs) |
| Best for | Heavy logic, DB calls | Fast middleware, redirects |
| Cold starts | Possible | Minimal |
On-demand routes and endpoints
Pages and endpoints render on the server when prerendering is disabled. A server endpoint receives a standard APIContext and returns a Response.
// src/pages/api/time.ts
import type { APIRoute } from 'astro';
export const prerender = false;
export const GET: APIRoute = async () => {
const now = new Date().toISOString();
return new Response(JSON.stringify({ now }), {
headers: { 'Content-Type': 'application/json' },
});
};
Hitting the deployed endpoint returns live data on each request.
Output:
{"now":"2026-06-14T10:42:08.317Z"}
A dynamic page works the same way — disable prerendering and read request data inside the component script. Islands hydrate only where marked.
---
// src/pages/greeting.astro
export const prerender = false;
const name = Astro.url.searchParams.get('name') ?? 'world';
---
<html>
<body>
<h1>Hello, {name}!</h1>
</body>
</html>
Accessing the Netlify context
Inside on-demand routes you can read Netlify-specific request context — such as geolocation and the incoming request — through standard Astro APIs and the platform headers Netlify injects.
// src/pages/api/where.ts
import type { APIRoute } from 'astro';
export const prerender = false;
export const GET: APIRoute = ({ request }) => {
const country = request.headers.get('x-nf-geo')
? JSON.parse(request.headers.get('x-nf-geo')!).country?.code
: 'unknown';
return new Response(`You are in ${country}`);
};
Image optimization and caching
The adapter integrates with Netlify Image CDN so Astro’s <Image /> component can transform images on demand. You can also enable static asset caching and on-demand revalidation through the imageCDN and caching options.
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify';
export default defineConfig({
output: 'server',
adapter: netlify({
imageCDN: true,
}),
});
Disable
imageCDNif you serve images from an external provider or do your own optimization, since routing them through Netlify’s CDN adds no benefit and may double-transform assets.
Deploying
Commit a netlify.toml (or configure the build in the Netlify dashboard) so Netlify knows the build command and publish directory. The adapter outputs functions automatically during the Astro build.
# netlify.toml
[build]
command = "astro build"
publish = "dist"
Then deploy via Git integration or the Netlify CLI.
npx netlify deploy --build --prod
Best practices
- Keep most routes static and opt into on-demand rendering per route with
export const prerender = falserather than flipping the whole site tooutput: 'server'. - Use Edge Functions for lightweight, latency-sensitive middleware (auth checks, redirects, A/B routing) and standard Functions for heavy logic or database access.
- Read geolocation and request metadata from Netlify’s injected headers instead of bundling extra dependencies.
- Enable
imageCDNonly when Netlify is actually serving your images, to avoid redundant transformation. - Pin the adapter version and align it with your Astro major version to avoid runtime mismatches.
- Test functions locally with
netlify devbefore pushing to catch runtime-specific issues early.