From 0e857ee3dc86e960b2bc906a6e096c8db2b2c7cc Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Wed, 5 Nov 2025 15:22:37 +0100 Subject: [PATCH 01/21] refactor(adapter-reference): type code block to docs + reorganization --- .../docs/en/reference/adapter-reference.mdx | 909 ++++++++++-------- 1 file changed, 510 insertions(+), 399 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 0a3fe53407f5e..a82ad54148f93 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -4,26 +4,24 @@ sidebar: label: Adapter API i18nReady: true --- +import ReadMore from '~/components/ReadMore.astro'; import Since from '~/components/Since.astro'; import { FileTree } from '@astrojs/starlight/components'; - Astro is designed to make it easy to deploy to any cloud provider for on-demand rendering, also known as server-side rendering (SSR). This ability is provided by __adapters__, which are [integrations](/en/reference/integrations-reference/). See the [on-demand rendering guide](/en/guides/on-demand-rendering/) to learn how to use an existing adapter. ## What is an adapter? -An adapter is a special kind of [integration](/en/reference/integrations-reference/) that provides an entrypoint for server rendering at request time. An adapter does two things: +An adapter is a special kind of [integration](/en/reference/integrations-reference/) that provides an entrypoint for server rendering at request time. An adapter has access to the full Integration API and does two things: - Implements host-specific APIs for handling requests. - Configures the build according to host conventions. -## Building an Adapter - -An adapter is an [integration](/en/reference/integrations-reference/) and can do anything that an integration can do. +## Building an adapter -An adapter __must__ call the `setAdapter` API in the `astro:config:done` hook like so: +To build an adapter, you need to create an integration and call the `setAdapter()` function in the [`astro:config:done` hook](/en/reference/integrations-reference/#astroconfigdone). The following example creates an adapter with a server entrypoint and stable support for Astro static output: -```js title="my-adapter.mjs" +```js title="my-adapter.mjs" {5-13} "setAdapter" export default function createIntegration() { return { name: '@example/my-adapter', @@ -42,122 +40,47 @@ export default function createIntegration() { } ``` -The object passed into `setAdapter` is defined as: - -```ts -interface AstroAdapter { - name: string; - serverEntrypoint?: string; - previewEntrypoint?: string; - exports?: string[]; - args?: any; - adapterFeatures?: AstroAdapterFeatures; - supportedAstroFeatures: AstroAdapterFeatureMap; - client?: { - /** - * Headers to inject into Astro's internal fetch calls (Actions, View Transitions, Server Islands, Prefetch). - * Can be an object of headers or a function that returns headers. - */ - internalFetchHeaders?: Record | (() => Record); - /** - * Query parameters to append to all asset URLs (images, stylesheets, scripts, etc.). - * Useful for adapters that need to track deployment versions or other metadata. - */ - assetQueryParams?: URLSearchParams; - }; -} - -export interface AstroAdapterFeatures { - /** - * Creates an edge function that will communicate with the Astro middleware. - */ - edgeMiddleware: boolean; - /** - * Determine the type of build output the adapter is intended for. Defaults to `server`; - */ - buildOutput?: 'static' | 'server'; -} +The `setAdapter` function accepts an object containing the following properties: -export type AdapterSupportsKind = 'unsupported' | 'stable' | 'experimental' | 'deprecated' | 'limited'; +### `name` -export type AdapterSupportWithMessage = { - support: Exclude; - message: string; - suppress?: 'default' | 'all'; -}; +

-export type AdapterSupport = AdapterSupportsKind | AdapterSupportWithMessage; - -export type AstroAdapterFeatureMap = { - /** - * The adapter is able to serve static pages - */ - staticOutput?: AdapterSupport; - /** - * The adapter is able to serve pages that are static or rendered via server - */ - hybridOutput?: AdapterSupport; - /** - * The adapter is able to serve pages rendered on demand - */ - serverOutput?: AdapterSupport; - /** - * The adapter is able to support i18n domains - */ - i18nDomains?: AdapterSupport; - /** - * The adapter is able to support `getSecret` exported from `astro:env/server` - */ - envGetSecret?: AdapterSupport; - /** - * The adapter supports the Sharp image service - */ - sharpImageService?: AdapterSupport; -}; -``` +**Type:** `string` +

-The properties are: +Defines a unique name for your adapter, used for logging. -* __name__: A unique name for your adapter, used for logging. -* __serverEntrypoint__: The entrypoint for on-demand server rendering. -* __exports__: An array of named exports when used in conjunction with `createExports` (explained below). -* __adapterFeatures__: An object that enables specific features that must be supported by the adapter. - These features will change the built output, and the adapter must implement the proper logic to handle the different output. -* __supportedAstroFeatures__: A map of Astro built-in features. This allows Astro to determine which features an adapter is unable or unwilling to support so appropriate error messages can be provided. +### `serverEntrypoint` -### Server Entrypoint +

-Astro's adapter API attempts to work with any type of host, and gives a flexible way to conform to the host APIs. +**Type:** `string | URL` +

-#### Exports +Defines the entrypoint for on-demand server rendering. -Some serverless hosts expect you to export a function, such as `handler`: +Learn more about [building a server entrypoint](#building-a-server-entrypoint) that matches your host. -```js -export function handler(event, context) { - // ... -} -``` +### `supportedAstroFeatures` -With the adapter API you achieve this by implementing `createExports` in your `serverEntrypoint`: +

-```js -import { App } from 'astro/app'; +**Type:** `AstroAdapterFeatureMap`
+ +

-export function createExports(manifest) { - const app = new App(manifest); +A map of Astro built-in features supported by the adapter. This allows Astro to determine which features an adapter is unable or unwilling to support so appropriate error messages can be provided. - const handler = (event, context) => { - // ... - }; +When using these properties, Astro will: +- run specific validation; +- emit contextual information to the logs; - return { handler }; -} -``` +These operations are run based on the features supported or not supported, their level of support, the [desired amount of logging](#suppress), and the user's own configuration. -And then in your integration, where you call `setAdapter`, provide this name in `exports`: +The following configuration tells Astro that this adapter has experimental support for the Sharp-powered built-in image service: -```js title="my-adapter.mjs" ins={9} +```js title="my-adapter.mjs" ins={9-11} export default function createIntegration() { return { name: '@example/my-adapter', @@ -166,7 +89,9 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - exports: ['handler'], + supportedAstroFeatures: { + sharpImageService: 'experimental' + } }); }, }, @@ -174,221 +99,184 @@ export default function createIntegration() { } ``` -#### Start - -Some hosts expect you to *start* the server yourselves, for example by listening to a port. For these types of hosts, the adapter API allows you to export a `start` function which will be called when the bundle script is run. - -```js -import { App } from 'astro/app'; - -export function start(manifest) { - const app = new App(manifest); +If the Sharp image service is used, Astro will log a warning and error to the terminal based on your adapter's support: - addEventListener('fetch', event => { - // ... - }); -} ``` +[@example/my-adapter] The feature is experimental and subject to issues or changes. -#### `astro/app` - -This module is used for rendering pages that have been prebuilt through `astro build`. Astro uses the standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. Hosts that have a different API for request/response should convert to these types in their adapter. - -```js -import { App } from 'astro/app'; -import http from 'http'; +[@example/my-adapter] The currently selected adapter `@example/my-adapter` is not compatible with the service "Sharp". Your project will NOT be able to build. +``` -export function start(manifest) { - const app = new App(manifest); +A message can additionally be provided to give more context to the user: - addEventListener('fetch', event => { - event.respondWith( - app.render(event.request) - ); - }); +```js title="my-adapter.mjs" ins={9-14} +export default function createIntegration() { + return { + name: '@example/my-adapter', + hooks: { + 'astro:config:done': ({ setAdapter }) => { + setAdapter({ + name: '@example/my-adapter', + serverEntrypoint: '@example/my-adapter/server.js', + supportedAstroFeatures: { + sharpImageService: { + support: 'limited', + message: 'This adapter has limited support for Sharp. Certain features may not work as expected.' + } + } + }); + }, + }, + }; } ``` -The following methods are provided: +This object contains the following configurable features: -##### `app.render()` +#### `staticOutput`

-**Type:** `(request: Request, options?: RenderOptions) => Promise` +**Type:** [`AdapterSupport`](#adaptersupport)

-This method calls the Astro page that matches the request, renders it, and returns a Promise to a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. This also works for API routes that do not render pages. - -```js -const response = await app.render(request); -``` +Defines whether the adapter is able to serve static pages. -##### `RenderOptions` +#### `hybridOutput`

-**Type:** `{addCookieHeader?: boolean; clientAddress?: string; locals?: object; prerenderedErrorPageFetch?: (url: ErrorPagePath) => Promise; routeData?: RouteData;}` +**Type:** [`AdapterSupport`](#adaptersupport)

-The `app.render()` method accepts a mandatory `request` argument, and an optional `RenderOptions` object for [`addCookieHeader`](#addcookieheader), [`clientAddress`](#clientaddress), [`locals`](#locals), [`prerenderedErrorPageFetch`](#prerenderederrorpagefetch), and [`routeData`](#routedata). +Defines whether the adapter is able to serve pages that are static or on-demand rendered. -###### `addCookieHeader` +#### `serverOutput`

-**Type:** `boolean`
-**Default:** `false` +**Type:** [`AdapterSupport`](#adaptersupport)

-Whether or not to automatically add all cookies written by `Astro.cookie.set()` to the response headers. - -When set to `true`, they will be added to the `Set-Cookie` header of the response as comma separated key-value pairs. You can use the standard `response.headers.getSetCookie()` API to read them individually. -When set to `false`(default), the cookies will only be available from `App.getSetCookieFromResponse(response)`. - -```js -const response = await app.render(request, { addCookieHeader: true }); -``` +Defines whether the adapter is able to serve on-demand pages. -###### `clientAddress` +#### `i18nDomains`

-**Type:** `string`
-**Default:** `request[Symbol.for("astro.clientAddress")]` +**Type:** [`AdapterSupport`](#adaptersupport)
+

-The client IP address that will be made available as [`Astro.clientAddress`](/en/reference/api-reference/#clientaddress) in pages, and as `ctx.clientAddress` in API routes and middleware. - -The example below reads the `x-forwarded-for` header and passes it as `clientAddress`. This value becomes available to the user as `Astro.clientAddress`. - -```js "clientAddress" -const clientAddress = request.headers.get("x-forwarded-for"); -const response = await app.render(request, { clientAddress }); -``` +Defines whether the adapter is able to support i18n domains. -###### `locals` +#### `envGetSecret`

-**Type:** `object` +**Type:** [`AdapterSupport`](#adaptersupport)
+

-The [`context.locals` object](/en/reference/api-reference/#locals) used to store and access information during the lifecycle of a request. +Defines whether the adapter is able to support `getSecret()` exported from [`astro:env/server`](/en/reference/modules/astro-env/). When enabled, this feature allows your adapter to retrieve secrets configured by users in `env.schema`. -The example below reads a header named `x-private-header`, attempts to parse it as an object and pass it to `locals`, which can then be passed to any [middleware function](/en/guides/middleware/). +The following example enables the feature by passing [a valid `AdapterSupportsKind` value](#adaptersupportskind) to the adapter: -```js "locals" -const privateHeader = request.headers.get("x-private-header"); -let locals = {}; -try { - if (privateHeader) { - locals = JSON.parse(privateHeader); - } -} finally { - const response = await app.render(request, { locals }); +```js title="my-adapter.mjs" ins={9-11} +export default function createIntegration() { + return { + name: '@example/my-adapter', + hooks: { + 'astro:config:done': ({ setAdapter }) => { + setAdapter({ + name: '@example/my-adapter', + serverEntrypoint: '@example/my-adapter/server.js', + supportedAstroFeatures: { + envGetSecret: 'stable' + } + }); + }, + }, + }; } ``` -###### `prerenderedErrorPageFetch` +The `astro/env/setup` module allows you to provide an implementation for `getSecret()`. In your server entrypoint, call `setGetEnv()` as soon as possible: -

+```js ins={2,4} +import { App } from 'astro/app'; +import { setGetEnv } from "astro/env/setup" -**Type:** `(url: ErrorPagePath) => Promise`
-**Default:** `fetch`
- -

+setGetEnv((key) => process.env[key]) -A function that allows you to provide custom implementations for fetching prerendered error pages. +export function createExports(manifest) { + const app = new App(manifest); -This is used to override the default `fetch()` behavior, for example, when `fetch()` is unavailable or when you cannot call the server from itself. + const handler = (event, context) => { + // ... + }; -The following example reads `500.html` and `404.html` from disk instead of performing an HTTP call: + return { handler }; +} +``` -```js "prerenderedErrorPageFetch" -return app.render(request, { - prerenderedErrorPageFetch: async (url: string): Promise => { - if (url.includes("/500")) { - const content = await fs.promises.readFile("500.html", "utf-8"); - return new Response(content, { - status: 500, - headers: { "Content-Type": "text/html" }, - }); - } +If you support secrets, be sure to call `setGetEnv()` before `getSecret()` when your environment variables are tied to the request: - const content = await fs.promises.readFile("404.html", "utf-8"); - return new Response(content, { - status: 404, - headers: { "Content-Type": "text/html" }, - }); -}); -``` +```js ins={3,14} +import type { SSRManifest } from 'astro'; +import { App } from 'astro/app'; +import { setGetEnv } from 'astro/env/setup'; +import { createGetEnv } from '../utils/env.js'; -If not provided, Astro will fallback to its default behavior for fetching error pages. +type Env = { + [key: string]: unknown; +}; -###### `routeData` +export function createExports(manifest: SSRManifest) { + const app = new App(manifest); -

+ const fetch = async (request: Request, env: Env) => { + setGetEnv(createGetEnv(env)); -**Type:** `RouteData`
-**Default:** `app.match(request)` -

+ const response = await app.render(request); -Provide a value for [`integrationRouteData`](/en/reference/integrations-reference/#integrationroutedata-type-reference) if you already know the route to render. Doing so will bypass the internal call to [`app.match`](#appmatch) to determine the route to render. + return response; + }; -```js "routeData" -const routeData = app.match(request); -if (routeData) { - return app.render(request, { routeData }); -} else { - /* adapter-specific 404 response */ - return new Response(..., { status: 404 }); + return { default: { fetch } }; } ``` -##### `app.match()` +#### `sharpImageService`

-**Type:** `(request: Request) => RouteData | undefined` +**Type:** [`AdapterSupport`](#adaptersupport)
+

-This method is used to determine if a request is matched by the Astro app's routing rules. - -```js -if(app.match(request)) { - const response = await app.render(request); -} -``` - -You can usually call `app.render(request)` without using `.match` because Astro handles 404s if you provide a `404.astro` file. Use `app.match(request)` if you want to handle 404s in a different way. - -## Allow installation via `astro add` +Defines whether the adapter supports image transformation using the built-in Sharp image service. -[The `astro add` command](/en/reference/cli-reference/#astro-add) allows users to easily add integrations and adapters to their project. If you want _your_ adapter to be installable with this tool, **add `astro-adapter` to the `keywords` field in your `package.json`**: +### `adapterFeatures` -```json -{ - "name": "example", - "keywords": ["astro-adapter"], -} -``` +

-Once you [publish your adapter to npm](https://docs.npmjs.com/cli/v8/commands/npm-publish), running `astro add example` will install your package with any peer dependencies specified in your `package.json`. We will also instruct users to update their project config manually. +**Type:** `AstroAdapterFeatures`
+ +

-## Astro features +A set of features that changes the output of the emitted files. When an adapter opts in to these features, they will get additional information inside specific hooks and must implement the proper logic to handle the different output. -

+#### `edgeMiddleware` -Astro features are a way for an adapter to tell Astro whether they are able to support a feature, and also the adapter's level of support. +

-When using these properties, Astro will: -- run specific validation; -- emit contextual information to the logs; +**Type:** `boolean` +

-These operations are run based on the features supported or not supported, their level of support, the [desired amount of logging](#suppress), and the user's own configuration. +Defines whether any on-demand rendering middleware code will be bundled when built. -The following configuration tells Astro that this adapter has experimental support for the Sharp-powered built-in image service: +When enabled, this prevents middleware code from being bundled and imported by all pages during the build: ```js title="my-adapter.mjs" ins={9-11} export default function createIntegration() { @@ -399,8 +287,8 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - supportedAstroFeatures: { - sharpImageService: 'experimental' + adapterFeatures: { + edgeMiddleware: true } }); }, @@ -409,17 +297,9 @@ export default function createIntegration() { } ``` -If the Sharp image service is used, Astro will log a warning and error to the terminal based on your adapter's support: +Then, consume the hook [`astro:build:ssr`](/en/reference/integrations-reference/#astrobuildssr), which will give you a `middlewareEntryPoint`, an `URL` to the physical file on the file system. -``` -[@example/my-adapter] The feature is experimental and subject to issues or changes. - -[@example/my-adapter] The currently selected adapter `@example/my-adapter` is not compatible with the service "Sharp". Your project will NOT be able to build. -``` - -A message can additionally be provided to give more context to the user: - -```js title="my-adapter.mjs" ins={9-14} +```js title="my-adapter.mjs" ins={15-20} export default function createIntegration() { return { name: '@example/my-adapter', @@ -428,32 +308,39 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - supportedAstroFeatures: { - sharpImageService: { - support: 'limited', - message: 'This adapter has limited support for Sharp. Certain features may not work as expected.' - } + adapterFeatures: { + edgeMiddleware: true } }); }, + + 'astro:build:ssr': ({ middlewareEntryPoint }) => { + // remember to check if this property exits, it will be `undefined` if the adapter doesn't opt in to the feature + if (middlewareEntryPoint) { + createEdgeMiddleware(middlewareEntryPoint) + } + } }, }; } + +function createEdgeMiddleware(middlewareEntryPoint) { + // emit a new physical file using your bundler +} ``` -### `suppress` +#### `buildOutput`

- **Type:** `'default' | 'all'`
- +**Type:** `"static" | "server"`
+**Default:** `"server"`
+

-An option to prevent showing some or all logged messages about an adapter's support for a feature. - -If Astro's default log message is redundant, or confusing to the user in combination with your custom `message`, you can use `suppress: "default"` to suppress the default message and only log your message: +Allows you to force a specific output shape for the build. This can be useful for adapters that only work with a specific output type, for instance, your adapter might expect a static website, but uses an adapter to create host-specific files. Defaults to `server` if not specified. -```js title="my-adapter.mjs" ins={13} +```js title="my-adapter.mjs" ins={9-11} export default function createIntegration() { return { name: '@example/my-adapter', @@ -462,12 +349,8 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - supportedAstroFeatures: { - sharpImageService: { - support: 'limited', - message: 'The adapter has limited support for Sharp. It will be used for images during build time, but will not work at runtime.', - suppress: 'default' // custom message is more detailed than the default - } + adapterFeatures: { + buildOutput: 'static' } }); }, @@ -476,9 +359,21 @@ export default function createIntegration() { } ``` -You can also use `suppress: "all"` to suppress all messages about support for the feature. This is useful when these messages are unhelpful to users in a specific context, such as when they have a configuration setting that means they are not using that feature. For example, you can choose to prevent logging any messages about Sharp support from your adapter: +#### `experimentalStaticHeaders` -```js title="my-adapter.mjs" ins={13} +

+ +**Type:** `boolean`
+ +

+ +When this feature is enabled, Astro will return a map of the `Headers` emitted by the static pages. This map `experimentalRouteToHeaders` is available in the [`astro:build:generated` hook](/en/reference/integrations-reference/#astrobuildgenerated). + +The value of the headers might change based on the features enabled/used by the application. + +For example, if [CSP is enabled](/en/reference/experimental-flags/csp/), the `` element is not added to the static page. Instead its `content` is available in the `experimentalRouteToHeaders` map. + +```js title="my-adapter.mjs" ins={9-11} export default function createIntegration() { return { name: '@example/my-adapter', @@ -487,57 +382,109 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - supportedAstroFeatures: { - sharpImageService: { - support: 'limited', - message: 'This adapter has limited support for Sharp. Certain features may not work as expected.', - suppress: 'all' - } - } + adapterFeatures: { + experimentalStaticHeaders: true, + }, }); }, + 'astro:build:generated': ({ experimentalRouteToHeaders }) => { + // use `experimentalRouteToHeaders` to generate a configuration file + // for your virtual host of choice + }, }, }; } ``` -## Adapter features +### `args` -A set of features that changes the output of the emitted files. When an adapter opts in to these features, they will get additional information inside specific hooks. +

+ +**Type:** `any` +

+ +{/* TODO: Find out what this does... `args` is not really the easiest thing to look for in a codebase. Maybe transmit integration options but to what? */} -### `edgeMiddleware` +### `client`

-**Type:** `boolean` +**Type:** `{ internalFetchHeaders?: Record | () => Record; assetQueryParams?: URLSearchParams; }`
+

-Defines whether any on-demand rendering middleware code will be bundled when built. +A configuration object for Astro's client-side code. -When enabled, this prevents middleware code from being bundled and imported by all pages during the build: +#### `internalFetchHeaders` -```js title="my-adapter.mjs" ins={9-11} -export default function createIntegration() { - return { - name: '@example/my-adapter', - hooks: { - 'astro:config:done': ({ setAdapter }) => { - setAdapter({ - name: '@example/my-adapter', - serverEntrypoint: '@example/my-adapter/server.js', - adapterFeatures: { - edgeMiddleware: true - } - }); - }, - }, +

+ +**Type:** `Record | () => Record` +

+ +Headers to inject into Astro's internal fetch calls (Actions, View Transitions, Server Islands, Prefetch). This can be an object of headers or a function that returns headers. + +#### `assetQueryParams` + +

+ +**Type:** `URLSearchParams` +

+ +Query parameters to append to all asset URLs (images, stylesheets, scripts, etc.). This is useful for adapters that need to track deployment versions or other metadata. + +### `exports` + +

+ +**Type:** `string[]` +

+ +An array of named exports when used in conjunction with the [`createExports()` function of your server entrypoint](/en/reference/adapter-reference/#exports-1). + +### `previewEntrypoint` + +

+ +**Type:** `string | URL`
+ +

+ +The path of a module in the adapter's package that is responsible of starting up the built server when `astro preview` is run. + +## Building a server entrypoint + +Astro's adapter API attempts to work with any type of host, and gives a flexible way to conform to the host APIs. + +### Exports + +Some serverless hosts expect you to export a function, such as `handler`: + +```js +export function handler(event, context) { + // ... +} +``` + +With the adapter API you achieve this by implementing `createExports` in your `serverEntrypoint`: + +```js +import { App } from 'astro/app'; + +export function createExports(manifest) { + const app = new App(manifest); + + const handler = (event, context) => { + // ... }; + + return { handler }; } ``` -Then, consume the hook [`astro:build:ssr`](/en/reference/integrations-reference/#astrobuildssr), which will give you a `middlewareEntryPoint`, an `URL` to the physical file on the file system. +And then in your integration, where you call `setAdapter`, provide this name in `exports`: -```js title="my-adapter.mjs" ins={15-20} +```js title="my-adapter.mjs" ins={9} export default function createIntegration() { return { name: '@example/my-adapter', @@ -546,114 +493,273 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - adapterFeatures: { - edgeMiddleware: true - } + exports: ['handler'], }); }, - - 'astro:build:ssr': ({ middlewareEntryPoint }) => { - // remember to check if this property exits, it will be `undefined` if the adapter doesn't opt in to the feature - if (middlewareEntryPoint) { - createEdgeMiddleware(middlewareEntryPoint) - } - } }, }; } +``` -function createEdgeMiddleware(middlewareEntryPoint) { - // emit a new physical file using your bundler +### Start + +Some hosts expect you to *start* the server yourselves, for example by listening to a port. For these types of hosts, the adapter API allows you to export a `start` function which will be called when the bundle script is run. + +```js +import { App } from 'astro/app'; + +export function start(manifest) { + const app = new App(manifest); + + addEventListener('fetch', event => { + // ... + }); } ``` -### envGetSecret +### `astro/app` + +This module is used for rendering pages that have been prebuilt through `astro build`. Astro uses the standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. Hosts that have a different API for request/response should convert to these types in their adapter. + +The `App` constructor requires an SSR manifest and you can pass an optional second argument to enable or disable streaming. + +```js +import { App } from 'astro/app'; +import http from 'http'; + +export function start(manifest) { + const app = new App(manifest); + + addEventListener('fetch', event => { + event.respondWith( + app.render(event.request) + ); + }); +} +``` + +The following methods are provided: + +#### `app.render()`

-**Type:** `AdapterSupportsKind` +**Type:** `(request: Request, options?: RenderOptions) => Promise`

-This is a feature to allow your adapter to retrieve secrets configured by users in `env.schema`. +This method calls the Astro page that matches the request, renders it, and returns a Promise to a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. This also works for API routes that do not render pages. -Enable the feature by passing any valid `AdapterSupportsKind` value to the adapter: +```js +const response = await app.render(request); +``` -```js title="my-adapter.mjs" ins={9-11} -export default function createIntegration() { - return { - name: '@example/my-adapter', - hooks: { - 'astro:config:done': ({ setAdapter }) => { - setAdapter({ - name: '@example/my-adapter', - serverEntrypoint: '@example/my-adapter/server.js', - adapterFeatures: { - envGetSecret: 'stable' - } - }); - }, - }, - }; -} +#### `RenderOptions` + +

+ +**Type:** `{addCookieHeader?: boolean; clientAddress?: string; locals?: object; prerenderedErrorPageFetch?: (url: ErrorPagePath) => Promise; routeData?: RouteData;}` +

+ +The `app.render()` method accepts a mandatory `request` argument, and an optional `RenderOptions` object for [`addCookieHeader`](#addcookieheader), [`clientAddress`](#clientaddress), [`locals`](#locals), [`prerenderedErrorPageFetch`](#prerenderederrorpagefetch), and [`routeData`](#routedata). + +##### `addCookieHeader` + +

+ +**Type:** `boolean`
+**Default:** `false` +

+ +Whether or not to automatically add all cookies written by `Astro.cookie.set()` to the response headers. + +When set to `true`, they will be added to the `Set-Cookie` header of the response as comma separated key-value pairs. You can use the standard `response.headers.getSetCookie()` API to read them individually. +When set to `false`(default), the cookies will only be available from `App.getSetCookieFromResponse(response)`. + +```js +const response = await app.render(request, { addCookieHeader: true }); ``` -The `astro/env/setup` module allows you to provide an implementation for `getSecret()`. In your server entrypoint, call `setGetEnv()` as soon as possible: +##### `clientAddress` -```js ins={2,4} -import { App } from 'astro/app'; -import { setGetEnv } from "astro/env/setup" +

-setGetEnv((key) => process.env[key]) +**Type:** `string`
+**Default:** `request[Symbol.for("astro.clientAddress")]` +

-export function createExports(manifest) { - const app = new App(manifest); +The client IP address that will be made available as [`Astro.clientAddress`](/en/reference/api-reference/#clientaddress) in pages, and as `ctx.clientAddress` in API routes and middleware. - const handler = (event, context) => { - // ... - }; +The example below reads the `x-forwarded-for` header and passes it as `clientAddress`. This value becomes available to the user as `Astro.clientAddress`. - return { handler }; +```js "clientAddress" +const clientAddress = request.headers.get("x-forwarded-for"); +const response = await app.render(request, { clientAddress }); +``` + +##### `locals` + +

+ +**Type:** `object` +

+ +The [`context.locals` object](/en/reference/api-reference/#locals) used to store and access information during the lifecycle of a request. + +The example below reads a header named `x-private-header`, attempts to parse it as an object and pass it to `locals`, which can then be passed to any [middleware function](/en/guides/middleware/). + +```js "locals" +const privateHeader = request.headers.get("x-private-header"); +let locals = {}; +try { + if (privateHeader) { + locals = JSON.parse(privateHeader); + } +} finally { + const response = await app.render(request, { locals }); } ``` -If you support secrets, be sure to call `setGetEnv()` before `getSecret()` when your environment variables are tied to the request: +##### `prerenderedErrorPageFetch` -```js ins={3,14} -import type { SSRManifest } from 'astro'; -import { App } from 'astro/app'; -import { setGetEnv } from 'astro/env/setup'; -import { createGetEnv } from '../utils/env.js'; +

-type Env = { - [key: string]: unknown; -}; +**Type:** `(url: ErrorPagePath) => Promise`
+**Default:** `fetch`
+ +

-export function createExports(manifest: SSRManifest) { - const app = new App(manifest); +A function that allows you to provide custom implementations for fetching prerendered error pages. - const fetch = async (request: Request, env: Env) => { - setGetEnv(createGetEnv(env)); +This is used to override the default `fetch()` behavior, for example, when `fetch()` is unavailable or when you cannot call the server from itself. - const response = await app.render(request); +The following example reads `500.html` and `404.html` from disk instead of performing an HTTP call: - return response; - }; +```js "prerenderedErrorPageFetch" +return app.render(request, { + prerenderedErrorPageFetch: async (url: string): Promise => { + if (url.includes("/500")) { + const content = await fs.promises.readFile("500.html", "utf-8"); + return new Response(content, { + status: 500, + headers: { "Content-Type": "text/html" }, + }); + } - return { default: { fetch } }; + const content = await fs.promises.readFile("404.html", "utf-8"); + return new Response(content, { + status: 404, + headers: { "Content-Type": "text/html" }, + }); +}); +``` + +If not provided, Astro will fallback to its default behavior for fetching error pages. + +##### `routeData` + +

+ +**Type:** `RouteData`
+**Default:** `app.match(request)` +

+ +Provide a value for [`integrationRouteData`](/en/reference/integrations-reference/#integrationroutedata-type-reference) if you already know the route to render. Doing so will bypass the internal call to [`app.match`](#appmatch) to determine the route to render. + +```js "routeData" +const routeData = app.match(request); +if (routeData) { + return app.render(request, { routeData }); +} else { + /* adapter-specific 404 response */ + return new Response(..., { status: 404 }); } ``` -### buildOutput +#### `app.match()`

-**Type:** `'static' | 'server'`
+**Type:** `(request: Request, allowPrerenderedRoutes = false) => RouteData | undefined` +

+ +Determines if a request is matched by the Astro app's routing rules. + +```js +if(app.match(request)) { + const response = await app.render(request); +} +``` + +You can usually call `app.render(request)` without using `.match` because Astro handles 404s if you provide a `404.astro` file. Use `app.match(request)` if you want to handle 404s in a different way. + +By default, prerendered routes aren't returned, even if they are matched. You can change this behavior by using `true` as second argument. + +## Adapter types reference + +### `AdapterSupport` + +

+ +**Type:** AdapterSupportsKind | AdapterSupportWithMessage

-This property allows you to force a specific output shape for the build. This can be useful for adapters that only work with a specific output type, for instance, your adapter might expect a static website, but uses an adapter to create host-specific files. Defaults to `server` if not specified. +A union of valid formats to describe the support level for a feature. -```js title="my-adapter.mjs" ins={9-11} +### `AdapterSupportsKind` + +

+ +**Type:** `"deprecated" | "experimental" | "limited" | "stable" | "unsupported"` +

+ +Defines the level of support for a feature by your adapter: +* Use `"deprecated"` when your adapter deprecates a feature support before completely removing its support in a future version. +* Use `"experimental"` when your adapter is adding support for a feature and issues or breaking changes are expected. +* Use `"limited"` when your adapter only supports a subset of the full feature. +* Use `"stable"` when the feature is fully supported by your adapter and stable. +* Use `"unsupported"` to warn users that they could have build issues in their project because this feature is not supported by your adapter. + +### `AdapterSupportWithMessage` + +

+ + +

+ +An object that allows you to define a support level for a feature and a message to be logged in the user console. This object contains the following properties: + +#### `support` + +

+ +**Type:** Exclude\<AdapterSupportsKind, "stable"\> +

+ +Defines the level of support for a feature by your adapter. + +#### `message` + +

+ +**Type:** `string` +

+ +A custom message to log regarding the support of a feature by your adapter. + +#### `suppress` + +

+ +**Type:** `"default" | "all"`
+ +

+ +An option to prevent showing some or all logged messages about an adapter's support for a feature. + +If Astro's default log message is redundant, or confusing to the user in combination with your [custom `message`](#message), you can use `suppress: "default"` to suppress the default message and only log your message: + +```js title="my-adapter.mjs" ins={13} export default function createIntegration() { return { name: '@example/my-adapter', @@ -662,8 +768,12 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - adapterFeatures: { - buildOutput: 'static' + supportedAstroFeatures: { + sharpImageService: { + support: 'limited', + message: 'The adapter has limited support for Sharp. It will be used for images during build time, but will not work at runtime.', + suppress: 'default' // custom message is more detailed than the default + } } }); }, @@ -672,21 +782,9 @@ export default function createIntegration() { } ``` -### experimentalStaticHeaders - -

- -**Type:** `true | false`
- -

- -When this feature is enabled, Astro will return a map of the `Headers` emitted by the static pages. This map `experimentalRouteToHeaders` is available in the `astro:build:generated` hook. - -The value of the headers might change based on the features enabled/used by the application. - -For example, if CSP enabled, the `` element is not added to the static page. Instead its `content` is available in the `experimentalRouteToHeaders` map. +You can also use `suppress: "all"` to suppress all messages about support for the feature. This is useful when these messages are unhelpful to users in a specific context, such as when they have a configuration setting that means they are not using that feature. For example, you can choose to prevent logging any messages about Sharp support from your adapter: -```js title="my-adapter.mjs" ins={9-11} +```js title="my-adapter.mjs" ins={13} export default function createIntegration() { return { name: '@example/my-adapter', @@ -695,16 +793,29 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - adapterFeatures: { - experimentalStaticHeaders: true, - }, + supportedAstroFeatures: { + sharpImageService: { + support: 'limited', + message: 'This adapter has limited support for Sharp. Certain features may not work as expected.', + suppress: 'all' + } + } }); }, - 'astro:build:generated': ({ experimentalRouteToHeaders }) => { - // use `experimentalRouteToHeaders` to generate a configuration file - // for your virtual host of choice - }, }, }; } ``` + +## Allow installation via `astro add` + +[The `astro add` command](/en/reference/cli-reference/#astro-add) allows users to easily add integrations and adapters to their project. If you want _your_ adapter to be installable with this tool, **add `astro-adapter` to the `keywords` field in your `package.json`**: + +```json +{ + "name": "example", + "keywords": ["astro-adapter"], +} +``` + +Once you [publish your adapter to npm](https://docs.npmjs.com/cli/v8/commands/npm-publish), running `astro add example` will install your package with any peer dependencies specified in your `package.json`. We will also instruct users to update their project config manually. From 9495dac6ed2c2b55834a24bc934cf700cdb23e65 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Wed, 5 Nov 2025 16:56:05 +0100 Subject: [PATCH 02/21] restore Astro features and Adapter features sections --- .../docs/en/reference/adapter-reference.mdx | 750 +++++++++--------- 1 file changed, 381 insertions(+), 369 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index a82ad54148f93..d7d5902280db5 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -72,117 +72,109 @@ Defines the entrypoint for on-demand server rendering. A map of Astro built-in features supported by the adapter. This allows Astro to determine which features an adapter is unable or unwilling to support so appropriate error messages can be provided. -When using these properties, Astro will: -- run specific validation; -- emit contextual information to the logs; +Discover the [available Astro features](#astro-features) that an adapter can configure. -These operations are run based on the features supported or not supported, their level of support, the [desired amount of logging](#suppress), and the user's own configuration. +### `adapterFeatures` -The following configuration tells Astro that this adapter has experimental support for the Sharp-powered built-in image service: +

-```js title="my-adapter.mjs" ins={9-11} -export default function createIntegration() { - return { - name: '@example/my-adapter', - hooks: { - 'astro:config:done': ({ setAdapter }) => { - setAdapter({ - name: '@example/my-adapter', - serverEntrypoint: '@example/my-adapter/server.js', - supportedAstroFeatures: { - sharpImageService: 'experimental' - } - }); - }, - }, - }; -} -``` +**Type:** `AstroAdapterFeatures`
+ +

-If the Sharp image service is used, Astro will log a warning and error to the terminal based on your adapter's support: +An object that enables specific features that must be supported by the adapter. These features will change the built output, and the adapter must implement the proper logic to handle the different output. -``` -[@example/my-adapter] The feature is experimental and subject to issues or changes. +Learn more about the [available features](#adapter-features) that an adapter can activate. -[@example/my-adapter] The currently selected adapter `@example/my-adapter` is not compatible with the service "Sharp". Your project will NOT be able to build. -``` +### `args` -A message can additionally be provided to give more context to the user: +

-```js title="my-adapter.mjs" ins={9-14} -export default function createIntegration() { - return { - name: '@example/my-adapter', - hooks: { - 'astro:config:done': ({ setAdapter }) => { - setAdapter({ - name: '@example/my-adapter', - serverEntrypoint: '@example/my-adapter/server.js', - supportedAstroFeatures: { - sharpImageService: { - support: 'limited', - message: 'This adapter has limited support for Sharp. Certain features may not work as expected.' - } - } - }); - }, - }, - }; -} -``` +**Type:** `any` +

-This object contains the following configurable features: +{/* TODO: Find out what this does... `args` is not really the easiest thing to look for in a codebase. Maybe transmit integration options but to what? */} -#### `staticOutput` +### `client`

-**Type:** [`AdapterSupport`](#adaptersupport) +**Type:** `{ internalFetchHeaders?: Record | () => Record; assetQueryParams?: URLSearchParams; }`
+

-Defines whether the adapter is able to serve static pages. +A configuration object for Astro's client-side code. -#### `hybridOutput` +#### `internalFetchHeaders`

-**Type:** [`AdapterSupport`](#adaptersupport) +**Type:** `Record | () => Record`

-Defines whether the adapter is able to serve pages that are static or on-demand rendered. +Headers to inject into Astro's internal fetch calls (Actions, View Transitions, Server Islands, Prefetch). This can be an object of headers or a function that returns headers. -#### `serverOutput` +#### `assetQueryParams`

-**Type:** [`AdapterSupport`](#adaptersupport) +**Type:** `URLSearchParams`

-Defines whether the adapter is able to serve on-demand pages. +Query parameters to append to all asset URLs (images, stylesheets, scripts, etc.). This is useful for adapters that need to track deployment versions or other metadata. -#### `i18nDomains` +### `exports`

-**Type:** [`AdapterSupport`](#adaptersupport)
- +**Type:** `string[]`

-Defines whether the adapter is able to support i18n domains. +An array of named exports when used in conjunction with the [`createExports()` function of your server entrypoint](/en/reference/adapter-reference/#exports-1). -#### `envGetSecret` +### `previewEntrypoint`

-**Type:** [`AdapterSupport`](#adaptersupport)
- +**Type:** `string | URL`
+

-Defines whether the adapter is able to support `getSecret()` exported from [`astro:env/server`](/en/reference/modules/astro-env/). When enabled, this feature allows your adapter to retrieve secrets configured by users in `env.schema`. +The path of a module in the adapter's package that is responsible of starting up the built server when `astro preview` is run. -The following example enables the feature by passing [a valid `AdapterSupportsKind` value](#adaptersupportskind) to the adapter: +## Building a server entrypoint -```js title="my-adapter.mjs" ins={9-11} +Astro's adapter API attempts to work with any type of host, and gives a flexible way to conform to the host APIs. + +### Exports + +Some serverless hosts expect you to export a function, such as `handler`: + +```js +export function handler(event, context) { + // ... +} +``` + +With the adapter API you achieve this by implementing `createExports` in your `serverEntrypoint`: + +```js +import { App } from 'astro/app'; + +export function createExports(manifest) { + const app = new App(manifest); + + const handler = (event, context) => { + // ... + }; + + return { handler }; +} +``` + +And then in your integration, where you call `setAdapter`, provide this name in `exports`: + +```js title="my-adapter.mjs" ins={9} export default function createIntegration() { return { name: '@example/my-adapter', @@ -191,9 +183,7 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - supportedAstroFeatures: { - envGetSecret: 'stable' - } + exports: ['handler'], }); }, }, @@ -201,144 +191,210 @@ export default function createIntegration() { } ``` -The `astro/env/setup` module allows you to provide an implementation for `getSecret()`. In your server entrypoint, call `setGetEnv()` as soon as possible: +### Start -```js ins={2,4} -import { App } from 'astro/app'; -import { setGetEnv } from "astro/env/setup" +Some hosts expect you to *start* the server yourselves, for example by listening to a port. For these types of hosts, the adapter API allows you to export a `start` function which will be called when the bundle script is run. -setGetEnv((key) => process.env[key]) +```js +import { App } from 'astro/app'; -export function createExports(manifest) { +export function start(manifest) { const app = new App(manifest); - const handler = (event, context) => { + addEventListener('fetch', event => { // ... - }; - - return { handler }; + }); } ``` -If you support secrets, be sure to call `setGetEnv()` before `getSecret()` when your environment variables are tied to the request: +### `astro/app` -```js ins={3,14} -import type { SSRManifest } from 'astro'; +This module is used for rendering pages that have been prebuilt through `astro build`. Astro uses the standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. Hosts that have a different API for request/response should convert to these types in their adapter. + +The `App` constructor requires an SSR manifest and you can pass an optional second argument to enable or disable streaming. + +```js import { App } from 'astro/app'; -import { setGetEnv } from 'astro/env/setup'; -import { createGetEnv } from '../utils/env.js'; +import http from 'http'; -type Env = { - [key: string]: unknown; -}; +export function start(manifest) { + const app = new App(manifest); -export function createExports(manifest: SSRManifest) { - const app = new App(manifest); + addEventListener('fetch', event => { + event.respondWith( + app.render(event.request) + ); + }); +} +``` - const fetch = async (request: Request, env: Env) => { - setGetEnv(createGetEnv(env)); +The following methods are provided: - const response = await app.render(request); +#### `app.render()` - return response; - }; +

- return { default: { fetch } }; -} +**Type:** `(request: Request, options?: RenderOptions) => Promise` +

+ +This method calls the Astro page that matches the request, renders it, and returns a Promise to a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. This also works for API routes that do not render pages. + +```js +const response = await app.render(request); ``` -#### `sharpImageService` +#### `RenderOptions`

-**Type:** [`AdapterSupport`](#adaptersupport)
- +**Type:** `{addCookieHeader?: boolean; clientAddress?: string; locals?: object; prerenderedErrorPageFetch?: (url: ErrorPagePath) => Promise; routeData?: RouteData;}`

-Defines whether the adapter supports image transformation using the built-in Sharp image service. +The `app.render()` method accepts a mandatory `request` argument, and an optional `RenderOptions` object for [`addCookieHeader`](#addcookieheader), [`clientAddress`](#clientaddress), [`locals`](#locals), [`prerenderedErrorPageFetch`](#prerenderederrorpagefetch), and [`routeData`](#routedata). -### `adapterFeatures` +##### `addCookieHeader`

-**Type:** `AstroAdapterFeatures`
- +**Type:** `boolean`
+**Default:** `false`

-A set of features that changes the output of the emitted files. When an adapter opts in to these features, they will get additional information inside specific hooks and must implement the proper logic to handle the different output. +Whether or not to automatically add all cookies written by `Astro.cookie.set()` to the response headers. -#### `edgeMiddleware` +When set to `true`, they will be added to the `Set-Cookie` header of the response as comma separated key-value pairs. You can use the standard `response.headers.getSetCookie()` API to read them individually. +When set to `false`(default), the cookies will only be available from `App.getSetCookieFromResponse(response)`. + +```js +const response = await app.render(request, { addCookieHeader: true }); +``` + +##### `clientAddress`

-**Type:** `boolean` +**Type:** `string`
+**Default:** `request[Symbol.for("astro.clientAddress")]`

-Defines whether any on-demand rendering middleware code will be bundled when built. +The client IP address that will be made available as [`Astro.clientAddress`](/en/reference/api-reference/#clientaddress) in pages, and as `ctx.clientAddress` in API routes and middleware. -When enabled, this prevents middleware code from being bundled and imported by all pages during the build: +The example below reads the `x-forwarded-for` header and passes it as `clientAddress`. This value becomes available to the user as `Astro.clientAddress`. -```js title="my-adapter.mjs" ins={9-11} -export default function createIntegration() { - return { - name: '@example/my-adapter', - hooks: { - 'astro:config:done': ({ setAdapter }) => { - setAdapter({ - name: '@example/my-adapter', - serverEntrypoint: '@example/my-adapter/server.js', - adapterFeatures: { - edgeMiddleware: true - } - }); - }, - }, - }; -} +```js "clientAddress" +const clientAddress = request.headers.get("x-forwarded-for"); +const response = await app.render(request, { clientAddress }); ``` -Then, consume the hook [`astro:build:ssr`](/en/reference/integrations-reference/#astrobuildssr), which will give you a `middlewareEntryPoint`, an `URL` to the physical file on the file system. +##### `locals` -```js title="my-adapter.mjs" ins={15-20} -export default function createIntegration() { - return { - name: '@example/my-adapter', - hooks: { - 'astro:config:done': ({ setAdapter }) => { - setAdapter({ - name: '@example/my-adapter', - serverEntrypoint: '@example/my-adapter/server.js', - adapterFeatures: { - edgeMiddleware: true - } - }); - }, +

- 'astro:build:ssr': ({ middlewareEntryPoint }) => { - // remember to check if this property exits, it will be `undefined` if the adapter doesn't opt in to the feature - if (middlewareEntryPoint) { - createEdgeMiddleware(middlewareEntryPoint) - } - } - }, - }; +**Type:** `object` +

+ +The [`context.locals` object](/en/reference/api-reference/#locals) used to store and access information during the lifecycle of a request. + +The example below reads a header named `x-private-header`, attempts to parse it as an object and pass it to `locals`, which can then be passed to any [middleware function](/en/guides/middleware/). + +```js "locals" +const privateHeader = request.headers.get("x-private-header"); +let locals = {}; +try { + if (privateHeader) { + locals = JSON.parse(privateHeader); + } +} finally { + const response = await app.render(request, { locals }); } +``` -function createEdgeMiddleware(middlewareEntryPoint) { - // emit a new physical file using your bundler +##### `prerenderedErrorPageFetch` + +

+ +**Type:** `(url: ErrorPagePath) => Promise`
+**Default:** `fetch`
+ +

+ +A function that allows you to provide custom implementations for fetching prerendered error pages. + +This is used to override the default `fetch()` behavior, for example, when `fetch()` is unavailable or when you cannot call the server from itself. + +The following example reads `500.html` and `404.html` from disk instead of performing an HTTP call: + +```js "prerenderedErrorPageFetch" +return app.render(request, { + prerenderedErrorPageFetch: async (url: string): Promise => { + if (url.includes("/500")) { + const content = await fs.promises.readFile("500.html", "utf-8"); + return new Response(content, { + status: 500, + headers: { "Content-Type": "text/html" }, + }); + } + + const content = await fs.promises.readFile("404.html", "utf-8"); + return new Response(content, { + status: 404, + headers: { "Content-Type": "text/html" }, + }); +}); +``` + +If not provided, Astro will fallback to its default behavior for fetching error pages. + +##### `routeData` + +

+ +**Type:** `RouteData`
+**Default:** `app.match(request)` +

+ +Provide a value for [`integrationRouteData`](/en/reference/integrations-reference/#integrationroutedata-type-reference) if you already know the route to render. Doing so will bypass the internal call to [`app.match`](#appmatch) to determine the route to render. + +```js "routeData" +const routeData = app.match(request); +if (routeData) { + return app.render(request, { routeData }); +} else { + /* adapter-specific 404 response */ + return new Response(..., { status: 404 }); } ``` -#### `buildOutput` +#### `app.match()`

-**Type:** `"static" | "server"`
-**Default:** `"server"`
- +**Type:** `(request: Request, allowPrerenderedRoutes = false) => RouteData | undefined`

-Allows you to force a specific output shape for the build. This can be useful for adapters that only work with a specific output type, for instance, your adapter might expect a static website, but uses an adapter to create host-specific files. Defaults to `server` if not specified. +Determines if a request is matched by the Astro app's routing rules. + +```js +if(app.match(request)) { + const response = await app.render(request); +} +``` + +You can usually call `app.render(request)` without using `.match` because Astro handles 404s if you provide a `404.astro` file. Use `app.match(request)` if you want to handle 404s in a different way. + +By default, prerendered routes aren't returned, even if they are matched. You can change this behavior by using `true` as second argument. + +## Astro features + +Astro features are a way for an adapter to tell Astro whether they are able to support a feature, and also the adapter’s level of support. + +When using these properties, Astro will: +- run specific validation; +- emit contextual information to the logs; + +These operations are run based on the features supported or not supported, their level of support, the [desired amount of logging](#suppress), and the user's own configuration. + +The following configuration tells Astro that this adapter has experimental support for the Sharp-powered built-in image service: ```js title="my-adapter.mjs" ins={9-11} export default function createIntegration() { @@ -349,8 +405,8 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - adapterFeatures: { - buildOutput: 'static' + supportedAstroFeatures: { + sharpImageService: 'experimental' } }); }, @@ -359,21 +415,17 @@ export default function createIntegration() { } ``` -#### `experimentalStaticHeaders` - -

+If the Sharp image service is used, Astro will log a warning and error to the terminal based on your adapter's support: -**Type:** `boolean`
- -

+``` +[@example/my-adapter] The feature is experimental and subject to issues or changes. -When this feature is enabled, Astro will return a map of the `Headers` emitted by the static pages. This map `experimentalRouteToHeaders` is available in the [`astro:build:generated` hook](/en/reference/integrations-reference/#astrobuildgenerated). - -The value of the headers might change based on the features enabled/used by the application. +[@example/my-adapter] The currently selected adapter `@example/my-adapter` is not compatible with the service "Sharp". Your project will NOT be able to build. +``` -For example, if [CSP is enabled](/en/reference/experimental-flags/csp/), the `` element is not added to the static page. Instead its `content` is available in the `experimentalRouteToHeaders` map. +A message can additionally be provided to give more context to the user: -```js title="my-adapter.mjs" ins={9-11} +```js title="my-adapter.mjs" ins={9-14} export default function createIntegration() { return { name: '@example/my-adapter', @@ -382,109 +434,71 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - adapterFeatures: { - experimentalStaticHeaders: true, - }, + supportedAstroFeatures: { + sharpImageService: { + support: 'limited', + message: 'This adapter has limited support for Sharp. Certain features may not work as expected.' + } + } }); }, - 'astro:build:generated': ({ experimentalRouteToHeaders }) => { - // use `experimentalRouteToHeaders` to generate a configuration file - // for your virtual host of choice - }, }, }; } ``` -### `args` - -

- -**Type:** `any` -

- -{/* TODO: Find out what this does... `args` is not really the easiest thing to look for in a codebase. Maybe transmit integration options but to what? */} +This object contains the following configurable features: -### `client` +#### `staticOutput`

-**Type:** `{ internalFetchHeaders?: Record | () => Record; assetQueryParams?: URLSearchParams; }`
- +**Type:** [`AdapterSupport`](#adaptersupport)

-A configuration object for Astro's client-side code. +Defines whether the adapter is able to serve static pages. -#### `internalFetchHeaders` +#### `hybridOutput`

-**Type:** `Record | () => Record` +**Type:** [`AdapterSupport`](#adaptersupport)

-Headers to inject into Astro's internal fetch calls (Actions, View Transitions, Server Islands, Prefetch). This can be an object of headers or a function that returns headers. +Defines whether the adapter is able to serve pages that are static or on-demand rendered. -#### `assetQueryParams` +#### `serverOutput`

-**Type:** `URLSearchParams` +**Type:** [`AdapterSupport`](#adaptersupport)

-Query parameters to append to all asset URLs (images, stylesheets, scripts, etc.). This is useful for adapters that need to track deployment versions or other metadata. +Defines whether the adapter is able to serve on-demand pages. -### `exports` +#### `i18nDomains`

-**Type:** `string[]` +**Type:** [`AdapterSupport`](#adaptersupport)
+

-An array of named exports when used in conjunction with the [`createExports()` function of your server entrypoint](/en/reference/adapter-reference/#exports-1). +Defines whether the adapter is able to support i18n domains. -### `previewEntrypoint` +#### `envGetSecret`

-**Type:** `string | URL`
- +**Type:** [`AdapterSupport`](#adaptersupport)
+

-The path of a module in the adapter's package that is responsible of starting up the built server when `astro preview` is run. - -## Building a server entrypoint - -Astro's adapter API attempts to work with any type of host, and gives a flexible way to conform to the host APIs. - -### Exports - -Some serverless hosts expect you to export a function, such as `handler`: - -```js -export function handler(event, context) { - // ... -} -``` - -With the adapter API you achieve this by implementing `createExports` in your `serverEntrypoint`: - -```js -import { App } from 'astro/app'; - -export function createExports(manifest) { - const app = new App(manifest); - - const handler = (event, context) => { - // ... - }; - - return { handler }; -} -``` +Defines whether the adapter is able to support `getSecret()` exported from [`astro:env/server`](/en/reference/modules/astro-env/). When enabled, this feature allows your adapter to retrieve secrets configured by users in `env.schema`. -And then in your integration, where you call `setAdapter`, provide this name in `exports`: +The following example enables the feature by passing [a valid `AdapterSupportsKind` value](#adaptersupportskind) to the adapter: -```js title="my-adapter.mjs" ins={9} +```js title="my-adapter.mjs" ins={9-11} export default function createIntegration() { return { name: '@example/my-adapter', @@ -493,7 +507,9 @@ export default function createIntegration() { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', - exports: ['handler'], + supportedAstroFeatures: { + envGetSecret: 'stable' + } }); }, }, @@ -501,199 +517,195 @@ export default function createIntegration() { } ``` -### Start - -Some hosts expect you to *start* the server yourselves, for example by listening to a port. For these types of hosts, the adapter API allows you to export a `start` function which will be called when the bundle script is run. +The `astro/env/setup` module allows you to provide an implementation for `getSecret()`. In your server entrypoint, call `setGetEnv()` as soon as possible: -```js +```js ins={2,4} import { App } from 'astro/app'; +import { setGetEnv } from "astro/env/setup" -export function start(manifest) { +setGetEnv((key) => process.env[key]) + +export function createExports(manifest) { const app = new App(manifest); - addEventListener('fetch', event => { + const handler = (event, context) => { // ... - }); + }; + + return { handler }; } ``` -### `astro/app` - -This module is used for rendering pages that have been prebuilt through `astro build`. Astro uses the standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. Hosts that have a different API for request/response should convert to these types in their adapter. - -The `App` constructor requires an SSR manifest and you can pass an optional second argument to enable or disable streaming. +If you support secrets, be sure to call `setGetEnv()` before `getSecret()` when your environment variables are tied to the request: -```js +```js ins={3,14} +import type { SSRManifest } from 'astro'; import { App } from 'astro/app'; -import http from 'http'; - -export function start(manifest) { - const app = new App(manifest); - - addEventListener('fetch', event => { - event.respondWith( - app.render(event.request) - ); - }); -} -``` +import { setGetEnv } from 'astro/env/setup'; +import { createGetEnv } from '../utils/env.js'; -The following methods are provided: +type Env = { + [key: string]: unknown; +}; -#### `app.render()` +export function createExports(manifest: SSRManifest) { + const app = new App(manifest); -

+ const fetch = async (request: Request, env: Env) => { + setGetEnv(createGetEnv(env)); -**Type:** `(request: Request, options?: RenderOptions) => Promise` -

+ const response = await app.render(request); -This method calls the Astro page that matches the request, renders it, and returns a Promise to a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. This also works for API routes that do not render pages. + return response; + }; -```js -const response = await app.render(request); + return { default: { fetch } }; +} ``` -#### `RenderOptions` - -

- -**Type:** `{addCookieHeader?: boolean; clientAddress?: string; locals?: object; prerenderedErrorPageFetch?: (url: ErrorPagePath) => Promise; routeData?: RouteData;}` -

- -The `app.render()` method accepts a mandatory `request` argument, and an optional `RenderOptions` object for [`addCookieHeader`](#addcookieheader), [`clientAddress`](#clientaddress), [`locals`](#locals), [`prerenderedErrorPageFetch`](#prerenderederrorpagefetch), and [`routeData`](#routedata). - -##### `addCookieHeader` +#### `sharpImageService`

-**Type:** `boolean`
-**Default:** `false` +**Type:** [`AdapterSupport`](#adaptersupport)
+

-Whether or not to automatically add all cookies written by `Astro.cookie.set()` to the response headers. +Defines whether the adapter supports image transformation using the built-in Sharp image service. -When set to `true`, they will be added to the `Set-Cookie` header of the response as comma separated key-value pairs. You can use the standard `response.headers.getSetCookie()` API to read them individually. -When set to `false`(default), the cookies will only be available from `App.getSetCookieFromResponse(response)`. +## Adapter features -```js -const response = await app.render(request, { addCookieHeader: true }); -``` +A set of features that changes the output of the emitted files. When an adapter opts in to these features, they will get additional information inside specific hooks and must implement the proper logic to handle the different output. -##### `clientAddress` +#### `edgeMiddleware`

-**Type:** `string`
-**Default:** `request[Symbol.for("astro.clientAddress")]` +**Type:** `boolean`

-The client IP address that will be made available as [`Astro.clientAddress`](/en/reference/api-reference/#clientaddress) in pages, and as `ctx.clientAddress` in API routes and middleware. +Defines whether any on-demand rendering middleware code will be bundled when built. -The example below reads the `x-forwarded-for` header and passes it as `clientAddress`. This value becomes available to the user as `Astro.clientAddress`. +When enabled, this prevents middleware code from being bundled and imported by all pages during the build: -```js "clientAddress" -const clientAddress = request.headers.get("x-forwarded-for"); -const response = await app.render(request, { clientAddress }); +```js title="my-adapter.mjs" ins={9-11} +export default function createIntegration() { + return { + name: '@example/my-adapter', + hooks: { + 'astro:config:done': ({ setAdapter }) => { + setAdapter({ + name: '@example/my-adapter', + serverEntrypoint: '@example/my-adapter/server.js', + adapterFeatures: { + edgeMiddleware: true + } + }); + }, + }, + }; +} ``` -##### `locals` - -

- -**Type:** `object` -

+Then, consume the hook [`astro:build:ssr`](/en/reference/integrations-reference/#astrobuildssr), which will give you a `middlewareEntryPoint`, an `URL` to the physical file on the file system. -The [`context.locals` object](/en/reference/api-reference/#locals) used to store and access information during the lifecycle of a request. +```js title="my-adapter.mjs" ins={15-20} +export default function createIntegration() { + return { + name: '@example/my-adapter', + hooks: { + 'astro:config:done': ({ setAdapter }) => { + setAdapter({ + name: '@example/my-adapter', + serverEntrypoint: '@example/my-adapter/server.js', + adapterFeatures: { + edgeMiddleware: true + } + }); + }, -The example below reads a header named `x-private-header`, attempts to parse it as an object and pass it to `locals`, which can then be passed to any [middleware function](/en/guides/middleware/). + 'astro:build:ssr': ({ middlewareEntryPoint }) => { + // remember to check if this property exits, it will be `undefined` if the adapter doesn't opt in to the feature + if (middlewareEntryPoint) { + createEdgeMiddleware(middlewareEntryPoint) + } + } + }, + }; +} -```js "locals" -const privateHeader = request.headers.get("x-private-header"); -let locals = {}; -try { - if (privateHeader) { - locals = JSON.parse(privateHeader); - } -} finally { - const response = await app.render(request, { locals }); +function createEdgeMiddleware(middlewareEntryPoint) { + // emit a new physical file using your bundler } ``` -##### `prerenderedErrorPageFetch` +#### `buildOutput`

-**Type:** `(url: ErrorPagePath) => Promise`
-**Default:** `fetch`
- +**Type:** `"static" | "server"`
+**Default:** `"server"`
+

-A function that allows you to provide custom implementations for fetching prerendered error pages. - -This is used to override the default `fetch()` behavior, for example, when `fetch()` is unavailable or when you cannot call the server from itself. - -The following example reads `500.html` and `404.html` from disk instead of performing an HTTP call: +Allows you to force a specific output shape for the build. This can be useful for adapters that only work with a specific output type, for instance, your adapter might expect a static website, but uses an adapter to create host-specific files. Defaults to `server` if not specified. -```js "prerenderedErrorPageFetch" -return app.render(request, { - prerenderedErrorPageFetch: async (url: string): Promise => { - if (url.includes("/500")) { - const content = await fs.promises.readFile("500.html", "utf-8"); - return new Response(content, { - status: 500, - headers: { "Content-Type": "text/html" }, +```js title="my-adapter.mjs" ins={9-11} +export default function createIntegration() { + return { + name: '@example/my-adapter', + hooks: { + 'astro:config:done': ({ setAdapter }) => { + setAdapter({ + name: '@example/my-adapter', + serverEntrypoint: '@example/my-adapter/server.js', + adapterFeatures: { + buildOutput: 'static' + } }); - } - - const content = await fs.promises.readFile("404.html", "utf-8"); - return new Response(content, { - status: 404, - headers: { "Content-Type": "text/html" }, - }); -}); -``` - -If not provided, Astro will fallback to its default behavior for fetching error pages. - -##### `routeData` - -

- -**Type:** `RouteData`
-**Default:** `app.match(request)` -

- -Provide a value for [`integrationRouteData`](/en/reference/integrations-reference/#integrationroutedata-type-reference) if you already know the route to render. Doing so will bypass the internal call to [`app.match`](#appmatch) to determine the route to render. - -```js "routeData" -const routeData = app.match(request); -if (routeData) { - return app.render(request, { routeData }); -} else { - /* adapter-specific 404 response */ - return new Response(..., { status: 404 }); + }, + }, + }; } ``` -#### `app.match()` +#### `experimentalStaticHeaders`

-**Type:** `(request: Request, allowPrerenderedRoutes = false) => RouteData | undefined` +**Type:** `boolean`
+

-Determines if a request is matched by the Astro app's routing rules. +When this feature is enabled, Astro will return a map of the `Headers` emitted by the static pages. This map `experimentalRouteToHeaders` is available in the [`astro:build:generated` hook](/en/reference/integrations-reference/#astrobuildgenerated). + +The value of the headers might change based on the features enabled/used by the application. -```js -if(app.match(request)) { - const response = await app.render(request); +For example, if [CSP is enabled](/en/reference/experimental-flags/csp/), the `` element is not added to the static page. Instead its `content` is available in the `experimentalRouteToHeaders` map. + +```js title="my-adapter.mjs" ins={9-11} +export default function createIntegration() { + return { + name: '@example/my-adapter', + hooks: { + 'astro:config:done': ({ setAdapter }) => { + setAdapter({ + name: '@example/my-adapter', + serverEntrypoint: '@example/my-adapter/server.js', + adapterFeatures: { + experimentalStaticHeaders: true, + }, + }); + }, + 'astro:build:generated': ({ experimentalRouteToHeaders }) => { + // use `experimentalRouteToHeaders` to generate a configuration file + // for your virtual host of choice + }, + }, + }; } ``` -You can usually call `app.render(request)` without using `.match` because Astro handles 404s if you provide a `404.astro` file. Use `app.match(request)` if you want to handle 404s in a different way. - -By default, prerendered routes aren't returned, even if they are matched. You can change this behavior by using `true` as second argument. - ## Adapter types reference ### `AdapterSupport` From 97b99266b70ac6a5d47545d712249a1e12d763fd Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Wed, 5 Nov 2025 18:18:49 +0100 Subject: [PATCH 03/21] add missing public APIs for astro/app --- .../docs/en/reference/adapter-reference.mdx | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index d7d5902280db5..12b68b9f0e32d 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -211,7 +211,7 @@ export function start(manifest) { This module is used for rendering pages that have been prebuilt through `astro build`. Astro uses the standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. Hosts that have a different API for request/response should convert to these types in their adapter. -The `App` constructor requires an SSR manifest and you can pass an optional second argument to enable or disable streaming. +The `App` constructor accepts a mandatory SSR manifest and an optional second argument to enable or disable streaming. ```js import { App } from 'astro/app'; @@ -384,6 +384,55 @@ You can usually call `app.render(request)` without using `.match` because Astro By default, prerendered routes aren't returned, even if they are matched. You can change this behavior by using `true` as second argument. +#### `app.getAdapterLogger()` + +

+ +**Type:** `() => AstroIntegrationLogger`
+ +

+ +Returns an [instance of the Astro logger](/en/reference/integrations-reference/#astrointegrationlogger) so that the adapter's runtime can use the same logger. + +#### `app.getAllowedDomains()` + +

+ +**Type:** `() => Partial[] | undefined`
+ +

+ +Returns a list of permitted host patterns for incoming requests when using SSR [as defined in the user configuration](/en/reference/configuration-reference/#securityalloweddomains). + +#### `app.removeBase()` + +

+ +**Type:** `(pathname: string) => string`
+ +

+ +Removes the base from the given path. This is useful when you need to look up assets from the filesystem. + +#### `app.setCookieHeaders()` + +

+ +**Type:** `(response: Response) => Generator`
+ +

+ +Returns a generator to set the cookies based on the given `Response`. + +#### `app.setManifestData` + +

+ +**Type:** `RoutesList` +

+ +Injects routes in the SSR manifest. + ## Astro features Astro features are a way for an adapter to tell Astro whether they are able to support a feature, and also the adapter’s level of support. From 5011db46dabd7b0405def91147435dafcaffd3bc Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Wed, 5 Nov 2025 18:35:42 +0100 Subject: [PATCH 04/21] fix heading levels now that the features sections are restored --- .../docs/en/reference/adapter-reference.mdx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 12b68b9f0e32d..4ed0d03b5a723 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -498,7 +498,7 @@ export default function createIntegration() { This object contains the following configurable features: -#### `staticOutput` +### `staticOutput`

@@ -507,7 +507,7 @@ This object contains the following configurable features: Defines whether the adapter is able to serve static pages. -#### `hybridOutput` +### `hybridOutput`

@@ -516,7 +516,7 @@ Defines whether the adapter is able to serve static pages. Defines whether the adapter is able to serve pages that are static or on-demand rendered. -#### `serverOutput` +### `serverOutput`

@@ -525,7 +525,7 @@ Defines whether the adapter is able to serve pages that are static or on-demand Defines whether the adapter is able to serve on-demand pages. -#### `i18nDomains` +### `i18nDomains`

@@ -535,7 +535,7 @@ Defines whether the adapter is able to serve on-demand pages. Defines whether the adapter is able to support i18n domains. -#### `envGetSecret` +### `envGetSecret`

@@ -612,7 +612,7 @@ export function createExports(manifest: SSRManifest) { } ``` -#### `sharpImageService` +### `sharpImageService`

@@ -626,7 +626,7 @@ Defines whether the adapter supports image transformation using the built-in Sha A set of features that changes the output of the emitted files. When an adapter opts in to these features, they will get additional information inside specific hooks and must implement the proper logic to handle the different output. -#### `edgeMiddleware` +### `edgeMiddleware`

@@ -688,7 +688,7 @@ function createEdgeMiddleware(middlewareEntryPoint) { } ``` -#### `buildOutput` +### `buildOutput`

@@ -718,7 +718,7 @@ export default function createIntegration() { } ``` -#### `experimentalStaticHeaders` +### `experimentalStaticHeaders`

From 9cafe3f29b18dd3c27528babb690ab8b1d3bda29 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Wed, 5 Nov 2025 18:48:13 +0100 Subject: [PATCH 05/21] RenderOptions can now be nested in app.render --- src/content/docs/en/reference/adapter-reference.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 4ed0d03b5a723..a60440f00d217 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -243,7 +243,7 @@ This method calls the Astro page that matches the request, renders it, and retur const response = await app.render(request); ``` -#### `RenderOptions` +##### `RenderOptions`

@@ -252,7 +252,7 @@ const response = await app.render(request); The `app.render()` method accepts a mandatory `request` argument, and an optional `RenderOptions` object for [`addCookieHeader`](#addcookieheader), [`clientAddress`](#clientaddress), [`locals`](#locals), [`prerenderedErrorPageFetch`](#prerenderederrorpagefetch), and [`routeData`](#routedata). -##### `addCookieHeader` +###### `addCookieHeader`

@@ -269,7 +269,7 @@ When set to `false`(default), the cookies will only be available from `App.getSe const response = await app.render(request, { addCookieHeader: true }); ``` -##### `clientAddress` +###### `clientAddress`

@@ -286,7 +286,7 @@ const clientAddress = request.headers.get("x-forwarded-for"); const response = await app.render(request, { clientAddress }); ``` -##### `locals` +###### `locals`

@@ -309,7 +309,7 @@ try { } ``` -##### `prerenderedErrorPageFetch` +###### `prerenderedErrorPageFetch`

@@ -345,7 +345,7 @@ return app.render(request, { If not provided, Astro will fallback to its default behavior for fetching error pages. -##### `routeData` +###### `routeData`

From 1978fa27cd9bb9a94c54c1406ccfb0e4ac5f7262 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 6 Nov 2025 12:37:12 +0100 Subject: [PATCH 06/21] small rewording --- .../docs/en/reference/adapter-reference.mdx | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index a60440f00d217..7a7ba9cb50df2 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -19,7 +19,9 @@ An adapter is a special kind of [integration](/en/reference/integrations-referen ## Building an adapter -To build an adapter, you need to create an integration and call the `setAdapter()` function in the [`astro:config:done` hook](/en/reference/integrations-reference/#astroconfigdone). The following example creates an adapter with a server entrypoint and stable support for Astro static output: +Create an integration and call the `setAdapter()` function in the [`astro:config:done`](/en/reference/integrations-reference/#astroconfigdone) hook. This allows you to define a server entrypoint and the features supported by your adapter. + +The following example creates an adapter with a server entrypoint and stable support for Astro static output: ```js title="my-adapter.mjs" {5-13} "setAdapter" export default function createIntegration() { @@ -49,7 +51,7 @@ The `setAdapter` function accepts an object containing the following properties: **Type:** `string`

-Defines a unique name for your adapter, used for logging. +Defines a unique name for your adapter. This will be used for logging. ### `serverEntrypoint` @@ -58,9 +60,9 @@ Defines a unique name for your adapter, used for logging. **Type:** `string | URL`

-Defines the entrypoint for on-demand server rendering. +Defines the entrypoint for on-demand rendering. -Learn more about [building a server entrypoint](#building-a-server-entrypoint) that matches your host. +Learn more about [building a server entrypoint](#building-a-server-entrypoint). ### `supportedAstroFeatures` @@ -112,7 +114,7 @@ A configuration object for Astro's client-side code. **Type:** `Record | () => Record`

-Headers to inject into Astro's internal fetch calls (Actions, View Transitions, Server Islands, Prefetch). This can be an object of headers or a function that returns headers. +Defines the headers to inject into Astro's internal fetch calls (e.g. Actions, View Transitions, Server Islands, Prefetch). This can be an object of headers or a function that returns headers. #### `assetQueryParams` @@ -121,7 +123,7 @@ Headers to inject into Astro's internal fetch calls (Actions, View Transitions, **Type:** `URLSearchParams`

-Query parameters to append to all asset URLs (images, stylesheets, scripts, etc.). This is useful for adapters that need to track deployment versions or other metadata. +Define the query parameters to append to all asset URLs (e.g. images, stylesheets, scripts, etc.). This is useful for adapters that need to track deployment versions or other metadata. ### `exports` @@ -130,7 +132,7 @@ Query parameters to append to all asset URLs (images, stylesheets, scripts, etc. **Type:** `string[]`

-An array of named exports when used in conjunction with the [`createExports()` function of your server entrypoint](/en/reference/adapter-reference/#exports-1). +Defines an array of named exports to use in conjunction with the [`createExports()` function](/en/reference/adapter-reference/#exports-1) of your server entrypoint. ### `previewEntrypoint` @@ -140,7 +142,7 @@ An array of named exports when used in conjunction with the [`createExports()` f

-The path of a module in the adapter's package that is responsible of starting up the built server when `astro preview` is run. +Defines the path of a module in the adapter's package that is responsible of starting up the built server when `astro preview` is run. ## Building a server entrypoint @@ -211,7 +213,7 @@ export function start(manifest) { This module is used for rendering pages that have been prebuilt through `astro build`. Astro uses the standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. Hosts that have a different API for request/response should convert to these types in their adapter. -The `App` constructor accepts a mandatory SSR manifest and an optional second argument to enable or disable streaming. +The `App` constructor accepts a mandatory SSR manifest and a second optional argument, defaulting to `true`, to enable or disable streaming. ```js import { App } from 'astro/app'; @@ -237,7 +239,7 @@ The following methods are provided: **Type:** `(request: Request, options?: RenderOptions) => Promise`

-This method calls the Astro page that matches the request, renders it, and returns a Promise to a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. This also works for API routes that do not render pages. +A method that accepts a mandatory `request` argument and an optional `RenderOptions` object. This calls the Astro page that matches the request, renders it, and returns a promise to a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. This also works for API routes that do not render pages. ```js const response = await app.render(request); @@ -250,7 +252,7 @@ const response = await app.render(request); **Type:** `{addCookieHeader?: boolean; clientAddress?: string; locals?: object; prerenderedErrorPageFetch?: (url: ErrorPagePath) => Promise; routeData?: RouteData;}`

-The `app.render()` method accepts a mandatory `request` argument, and an optional `RenderOptions` object for [`addCookieHeader`](#addcookieheader), [`clientAddress`](#clientaddress), [`locals`](#locals), [`prerenderedErrorPageFetch`](#prerenderederrorpagefetch), and [`routeData`](#routedata). +An object that controls the rendering and contains the following properties: ###### `addCookieHeader` @@ -309,7 +311,7 @@ try { } ``` -###### `prerenderedErrorPageFetch` +###### `prerenderedErrorPageFetch()`

@@ -566,7 +568,7 @@ export default function createIntegration() { } ``` -The `astro/env/setup` module allows you to provide an implementation for `getSecret()`. In your server entrypoint, call `setGetEnv()` as soon as possible: +The `astro/env/setup` module allows you to provide an implementation for `getSecret()`. In [your server entrypoint](#building-a-server-entrypoint), call `setGetEnv()` as soon as possible: ```js ins={2,4} import { App } from 'astro/app'; @@ -775,11 +777,11 @@ A union of valid formats to describe the support level for a feature.

Defines the level of support for a feature by your adapter: -* Use `"deprecated"` when your adapter deprecates a feature support before completely removing its support in a future version. -* Use `"experimental"` when your adapter is adding support for a feature and issues or breaking changes are expected. +* Use `"deprecated"` when your adapter deprecates a feature support before removing it completely in a future version. +* Use `"experimental"` when your adapter adds support for a feature and issues or breaking changes are expected. * Use `"limited"` when your adapter only supports a subset of the full feature. * Use `"stable"` when the feature is fully supported by your adapter and stable. -* Use `"unsupported"` to warn users that they could have build issues in their project because this feature is not supported by your adapter. +* Use `"unsupported"` to warn users that they may encounter build issues in their project, as this feature is not supported by your adapter. ### `AdapterSupportWithMessage` @@ -806,7 +808,7 @@ Defines the level of support for a feature by your adapter. **Type:** `string`

-A custom message to log regarding the support of a feature by your adapter. +Defines a custom message to log regarding the support of a feature by your adapter. #### `suppress` From a7eacaa79f9aaa45f7b5196d25f80bfb7fd9a1c9 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 6 Nov 2025 15:08:31 +0100 Subject: [PATCH 07/21] add docs for args --- src/content/docs/en/reference/adapter-reference.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 7a7ba9cb50df2..2d85d62538249 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -95,7 +95,7 @@ An object that enables specific features that must be supported by the adapter. **Type:** `any`

-{/* TODO: Find out what this does... `args` is not really the easiest thing to look for in a codebase. Maybe transmit integration options but to what? */} +A JSON-serializable value that will be passed to the adapter's server entrypoint at runtime. This is useful to pass an object containing build-time configuration (e.g. paths, secrets, etc.) to your server runtime code. ### `client` From e704ee65a4a52fb406282adc917fa29a454fcd02 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 6 Nov 2025 15:27:39 +0100 Subject: [PATCH 08/21] improve `setCookieHeaders` docs --- src/content/docs/en/reference/adapter-reference.mdx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 2d85d62538249..608fb3ff915d3 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -424,7 +424,17 @@ Removes the base from the given path. This is useful when you need to look up as

-Returns a generator to set the cookies based on the given `Response`. +Returns a generator that yields individual cookie header values from a `Response` object. This is used to properly handle multiple cookies that may have been set during request processing. + +The following example appends a `Set-Cookie` header for each header obtained from a response: + +```js +if (app.setCookieHeaders) { + for (const setCookieHeader of app.setCookieHeaders(response)) { + response.headers.append('Set-Cookie', setCookieHeader); + } +} +``` #### `app.setManifestData` From c676cc1d71c6b18db5977eb52016f35392b2b854 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 6 Nov 2025 15:28:04 +0100 Subject: [PATCH 09/21] remove `app.setManifestData` (leftover or internal thing I think) --- src/content/docs/en/reference/adapter-reference.mdx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 608fb3ff915d3..4946f54e55677 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -436,15 +436,6 @@ if (app.setCookieHeaders) { } ``` -#### `app.setManifestData` - -

- -**Type:** `RoutesList` -

- -Injects routes in the SSR manifest. - ## Astro features Astro features are a way for an adapter to tell Astro whether they are able to support a feature, and also the adapter’s level of support. From 534e2e81cced407f650a4b7280ba708a19f320fd Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 6 Nov 2025 15:57:56 +0100 Subject: [PATCH 10/21] add code snippets for `setAdapter` properties --- .../docs/en/reference/adapter-reference.mdx | 114 +++++++++++++++++- 1 file changed, 109 insertions(+), 5 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 4946f54e55677..2fe22b0ba3469 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -33,7 +33,7 @@ export default function createIntegration() { name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', supportedAstroFeatures: { - staticOutput: 'stable' + staticOutput: 'stable' } }); }, @@ -42,7 +42,7 @@ export default function createIntegration() { } ``` -The `setAdapter` function accepts an object containing the following properties: +The `setAdapter()` function accepts an object containing the following properties: ### `name` @@ -97,6 +97,27 @@ An object that enables specific features that must be supported by the adapter. A JSON-serializable value that will be passed to the adapter's server entrypoint at runtime. This is useful to pass an object containing build-time configuration (e.g. paths, secrets, etc.) to your server runtime code. +The following example defines an `args` object to pass to [the server entrypoint](#building-a-server-entrypoint) the directory path in the build output where the resources generated by Astro are located: + +```js title="my-adapter.mjs" {9-11} +export default function createIntegration() { + return { + name: '@example/my-adapter', + hooks: { + 'astro:config:done': ({ config, setAdapter }) => { + setAdapter({ + name: '@example/my-adapter', + serverEntrypoint: '@example/my-adapter/server.js', + args: { + assets: config.build.assets + } + }); + }, + }, + }; +} +``` + ### `client`

@@ -116,6 +137,30 @@ A configuration object for Astro's client-side code. Defines the headers to inject into Astro's internal fetch calls (e.g. Actions, View Transitions, Server Islands, Prefetch). This can be an object of headers or a function that returns headers. +The following example retrieves a `DEPLOY_ID` from the environment variables and, if provided, returns an object with the header name as key and the deploy id as value: + +```js title="my-adapter.mjs" {9-14} +export default function createIntegration() { + return { + name: '@example/my-adapter', + hooks: { + 'astro:config:done': ({ config, setAdapter }) => { + setAdapter({ + name: '@example/my-adapter', + serverEntrypoint: '@example/my-adapter/server.js', + client: { + internalFetchHeaders: () => { + const deployId = process.env.DEPLOY_ID; + return deployId ? { 'Your-Header-ID': deployId } : {}; + }, + }, + }); + }, + }, + }; +} +``` + #### `assetQueryParams`

@@ -125,6 +170,29 @@ Defines the headers to inject into Astro's internal fetch calls (e.g. Actions, V Define the query parameters to append to all asset URLs (e.g. images, stylesheets, scripts, etc.). This is useful for adapters that need to track deployment versions or other metadata. +The following example retrieves a `DEPLOY_ID` from the environment variables and, if provided, returns an object with a custom search parameter name as key and the deploy id as value: + +```js title="my-adapter.mjs" {9-13} +export default function createIntegration() { + return { + name: '@example/my-adapter', + hooks: { + 'astro:config:done': ({ config, setAdapter }) => { + setAdapter({ + name: '@example/my-adapter', + serverEntrypoint: '@example/my-adapter/server.js', + client: { + assetQueryParams: process.env.DEPLOY_ID + ? new URLSearchParams({ yourParam: process.env.DEPLOY_ID }) + : undefined, + }, + }); + }, + }, + }; +} +``` + ### `exports`

@@ -132,7 +200,26 @@ Define the query parameters to append to all asset URLs (e.g. images, stylesheet **Type:** `string[]`

-Defines an array of named exports to use in conjunction with the [`createExports()` function](/en/reference/adapter-reference/#exports-1) of your server entrypoint. +Defines an array of named exports to use in conjunction with the [`createExports()` function](#exports-1) of your server entrypoint. + +The following example assumes that `createExports()` provides an export named `handler`: + +```js title="my-adapter.mjs" {9} +export default function createIntegration() { + return { + name: '@example/my-adapter', + hooks: { + 'astro:config:done': ({ config, setAdapter }) => { + setAdapter({ + name: '@example/my-adapter', + serverEntrypoint: '@example/my-adapter/server.js', + exports: ['handler'] + }); + }, + }, + }; +} +``` ### `previewEntrypoint` @@ -144,6 +231,23 @@ Defines an array of named exports to use in conjunction with the [`createExports Defines the path of a module in the adapter's package that is responsible of starting up the built server when `astro preview` is run. +```js title="my-adapter.mjs" {9} +export default function createIntegration() { + return { + name: '@example/my-adapter', + hooks: { + 'astro:config:done': ({ config, setAdapter }) => { + setAdapter({ + name: '@example/my-adapter', + serverEntrypoint: '@example/my-adapter/server.js', + previewEntrypoint: '@example/my-adapter/preview.js', + }); + }, + }, + }; +} +``` + ## Building a server entrypoint Astro's adapter API attempts to work with any type of host, and gives a flexible way to conform to the host APIs. @@ -160,7 +264,7 @@ export function handler(event, context) { With the adapter API you achieve this by implementing `createExports` in your `serverEntrypoint`: -```js +```js title="my-adapter/server.js" import { App } from 'astro/app'; export function createExports(manifest) { @@ -174,7 +278,7 @@ export function createExports(manifest) { } ``` -And then in your integration, where you call `setAdapter`, provide this name in `exports`: +And then in your integration, where you call `setAdapter`, provide this name in [`exports`](#exports): ```js title="my-adapter.mjs" ins={9} export default function createIntegration() { From 575b23a2eabdc5a5554fde2af4bdbf98ce466f6c Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 6 Nov 2025 16:27:28 +0100 Subject: [PATCH 11/21] adds docs for `createExports` second argument --- .../docs/en/reference/adapter-reference.mdx | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 2fe22b0ba3469..7cfaa8c224de6 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -262,7 +262,7 @@ export function handler(event, context) { } ``` -With the adapter API you achieve this by implementing `createExports` in your `serverEntrypoint`: +With the adapter API you achieve this by implementing `createExports()` in your `serverEntrypoint`: ```js title="my-adapter/server.js" import { App } from 'astro/app'; @@ -278,7 +278,7 @@ export function createExports(manifest) { } ``` -And then in your integration, where you call `setAdapter`, provide this name in [`exports`](#exports): +And then in your integration, where you call `setAdapter()`, provide this name in [`exports`](#exports): ```js title="my-adapter.mjs" ins={9} export default function createIntegration() { @@ -297,6 +297,18 @@ export default function createIntegration() { } ``` +The `createExports()` function accepts a second optional argument that retrieves the [arguments passed by the adapter](#args). This is useful when you need to access build-time configuration in your server entrypoint. + +```js title="my-adapter/server.js" +import { App } from 'astro/app'; + +export function createExports(manifest, args) { + const assetsPath = args.assets; + /* ... */ + return {}; +} +``` + ### Start Some hosts expect you to *start* the server yourselves, for example by listening to a port. For these types of hosts, the adapter API allows you to export a `start` function which will be called when the bundle script is run. @@ -500,6 +512,15 @@ By default, prerendered routes aren't returned, even if they are matched. You ca Returns an [instance of the Astro logger](/en/reference/integrations-reference/#astrointegrationlogger) so that the adapter's runtime can use the same logger. +```js "logger" +const logger = app.getAdapterLogger(); +try { + /* Some logic that can throw */ +} catch { + logger.error("Your custom error message using Astro logger."); +} +``` + #### `app.getAllowedDomains()`

From d38ac5882679468dd2902ab66e5736b24581d9b5 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 6 Nov 2025 17:38:40 +0100 Subject: [PATCH 12/21] update server entrypoint exports and start sections --- .../docs/en/reference/adapter-reference.mdx | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 7cfaa8c224de6..7ca005bbe0982 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -252,17 +252,16 @@ export default function createIntegration() { Astro's adapter API attempts to work with any type of host, and gives a flexible way to conform to the host APIs. -### Exports +### `createExports()` -Some serverless hosts expect you to export a function, such as `handler`: +

-```js -export function handler(event, context) { - // ... -} -``` +Type: `(manifest: SSRManifest, options: any) => Record` +

+ +An exported function that takes an SSR manifest as its first argument and an object containing your adapter [args](#args) as its second argument. This should provide the exports required by your host. -With the adapter API you achieve this by implementing `createExports()` in your `serverEntrypoint`: +For example, some serverless hosts expect you to export an `handler()` function. With the adapter API you achieve this by implementing `createExports()` in your server entrypoint: ```js title="my-adapter/server.js" import { App } from 'astro/app'; @@ -297,7 +296,7 @@ export default function createIntegration() { } ``` -The `createExports()` function accepts a second optional argument that retrieves the [arguments passed by the adapter](#args). This is useful when you need to access build-time configuration in your server entrypoint. +The `createExports()` second argument can be useful when you need to access build-time configuration in your server entrypoint. For example, your server entrypoint might need the directory path in the build output where the resources generated by Astro are located: ```js title="my-adapter/server.js" import { App } from 'astro/app'; @@ -309,11 +308,18 @@ export function createExports(manifest, args) { } ``` -### Start +### `start()` + +

+ +Type: `(manifest: SSRManifest, options: any) => Record` +

+ +An exported function that takes an SSR manifest as its first argument and an object containing your adapter [args](#args) as its second argument. Some hosts expect you to *start* the server yourselves, for example by listening to a port. For these types of hosts, the adapter API allows you to export a `start` function which will be called when the bundle script is run. -```js +```js title="my-adapter/server.js" import { App } from 'astro/app'; export function start(manifest) { From cb92f381d9dfe3f42d7600fe0c49f3a71e55a783 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 6 Nov 2025 17:52:29 +0100 Subject: [PATCH 13/21] fix link, should be ready now --- src/content/docs/en/reference/adapter-reference.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 7ca005bbe0982..fbd9ad7093bad 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -200,7 +200,7 @@ export default function createIntegration() { **Type:** `string[]`

-Defines an array of named exports to use in conjunction with the [`createExports()` function](#exports-1) of your server entrypoint. +Defines an array of named exports to use in conjunction with the [`createExports()` function](#createexports) of your server entrypoint. The following example assumes that `createExports()` provides an export named `handler`: From 9a9081ec2391b23967e0de93f8709b1948c42b03 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 7 Nov 2025 12:06:10 +0100 Subject: [PATCH 14/21] Matt's wording improvement Co-authored-by: Matt Kane --- .../docs/en/reference/adapter-reference.mdx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index fbd9ad7093bad..e70727191d9fb 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -229,7 +229,7 @@ export default function createIntegration() {

-Defines the path of a module in the adapter's package that is responsible of starting up the built server when `astro preview` is run. +Defines the path or ID of a module in the adapter's package that is responsible of starting up the built server when `astro preview` is run. ```js title="my-adapter.mjs" {9} export default function createIntegration() { @@ -296,7 +296,7 @@ export default function createIntegration() { } ``` -The `createExports()` second argument can be useful when you need to access build-time configuration in your server entrypoint. For example, your server entrypoint might need the directory path in the build output where the resources generated by Astro are located: +The second argument passed to `createExports()` can be useful when you need to access build-time configuration in your server entrypoint. For example, your server entrypoint might need the directory path in the build output where the resources generated by Astro are located: ```js title="my-adapter/server.js" import { App } from 'astro/app'; @@ -335,7 +335,7 @@ export function start(manifest) { This module is used for rendering pages that have been prebuilt through `astro build`. Astro uses the standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. Hosts that have a different API for request/response should convert to these types in their adapter. -The `App` constructor accepts a mandatory SSR manifest and a second optional argument, defaulting to `true`, to enable or disable streaming. +The `App` constructor accepts a required SSR manifest argument, and optionally an argument to enable or disable streaming, defaulting to `true`. ```js import { App } from 'astro/app'; @@ -361,7 +361,7 @@ The following methods are provided: **Type:** `(request: Request, options?: RenderOptions) => Promise`

-A method that accepts a mandatory `request` argument and an optional `RenderOptions` object. This calls the Astro page that matches the request, renders it, and returns a promise to a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. This also works for API routes that do not render pages. +A method that accepts a required `request` argument and an optional `RenderOptions` object. This calls the Astro page that matches the request, renders it, and returns a promise to a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. This also works for API routes that do not render pages. ```js const response = await app.render(request); @@ -648,7 +648,7 @@ Defines whether the adapter is able to serve static pages. **Type:** [`AdapterSupport`](#adaptersupport)

-Defines whether the adapter is able to serve pages that are static or on-demand rendered. +Defines whether the adapter is able to serve sites that include a mix of static and on-demand rendered pages. ### `serverOutput` @@ -657,7 +657,7 @@ Defines whether the adapter is able to serve pages that are static or on-demand **Type:** [`AdapterSupport`](#adaptersupport)

-Defines whether the adapter is able to serve on-demand pages. +Defines whether the adapter is able to serve on-demand rendered pages. ### `i18nDomains` @@ -719,7 +719,7 @@ export function createExports(manifest) { } ``` -If you support secrets, be sure to call `setGetEnv()` before `getSecret()` when your environment variables are tied to the request: +If the adapter supports secrets, be sure to call `setGetEnv()` before `getSecret()` when environment variables are tied to the request: ```js ins={3,14} import type { SSRManifest } from 'astro'; From 5041d53536a5d27e996c76ce1ca9858a211069d2 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 7 Nov 2025 12:17:18 +0100 Subject: [PATCH 15/21] add handler in createExports args snippet Co-authored-by: Matt Kane --- src/content/docs/en/reference/adapter-reference.mdx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index e70727191d9fb..d209f04b3949e 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -298,13 +298,17 @@ export default function createIntegration() { The second argument passed to `createExports()` can be useful when you need to access build-time configuration in your server entrypoint. For example, your server entrypoint might need the directory path in the build output where the resources generated by Astro are located: -```js title="my-adapter/server.js" +```js title="my-adapter/server.js" {4} "args" import { App } from 'astro/app'; export function createExports(manifest, args) { const assetsPath = args.assets; - /* ... */ - return {}; + + const handler = (event, context) => { + // ... + }; + + return { handler }; } ``` From d5bae1fc2ec8db2b118ba54377d95cd8b52ae8b8 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 7 Nov 2025 14:22:30 +0100 Subject: [PATCH 16/21] Sarah and Matt's improvements Co-authored-by: Matt Kane Co-authored-by: Sarah Rainsberger <5098874+sarah11918@users.noreply.github.com> --- .../docs/en/reference/adapter-reference.mdx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index d209f04b3949e..78ee7b9dd32de 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -72,7 +72,7 @@ Defines the entrypoint for on-demand rendering.

-A map of Astro built-in features supported by the adapter. This allows Astro to determine which features an adapter is unable or unwilling to support so appropriate error messages can be provided. +A map of Astro built-in features supported by the adapter. This allows Astro to determine which features an adapter supports so appropriate error messages can be provided. Discover the [available Astro features](#astro-features) that an adapter can configure. @@ -95,7 +95,7 @@ An object that enables specific features that must be supported by the adapter. **Type:** `any`

-A JSON-serializable value that will be passed to the adapter's server entrypoint at runtime. This is useful to pass an object containing build-time configuration (e.g. paths, secrets, etc.) to your server runtime code. +A JSON-serializable value that will be passed to the adapter's server entrypoint at runtime. This is useful to pass an object containing build-time configuration (e.g. paths, secrets) to your server runtime code. The following example defines an `args` object to pass to [the server entrypoint](#building-a-server-entrypoint) the directory path in the build output where the resources generated by Astro are located: @@ -229,7 +229,7 @@ export default function createIntegration() {

-Defines the path or ID of a module in the adapter's package that is responsible of starting up the built server when `astro preview` is run. +Defines the path or ID of a module in the adapter's package that is responsible for starting up the built server when `astro preview` is run. ```js title="my-adapter.mjs" {9} export default function createIntegration() { @@ -520,7 +520,7 @@ By default, prerendered routes aren't returned, even if they are matched. You ca

-Returns an [instance of the Astro logger](/en/reference/integrations-reference/#astrointegrationlogger) so that the adapter's runtime can use the same logger. +Returns an [instance of the Astro logger](/en/reference/integrations-reference/#astrointegrationlogger) available to the adapter's runtime environment. ```js "logger" const logger = app.getAdapterLogger(); @@ -835,7 +835,7 @@ function createEdgeMiddleware(middlewareEntryPoint) {

-Allows you to force a specific output shape for the build. This can be useful for adapters that only work with a specific output type, for instance, your adapter might expect a static website, but uses an adapter to create host-specific files. Defaults to `server` if not specified. +Allows you to force a specific output shape for the build. This can be useful for adapters that only work with a specific output type. For example, your adapter might expect a static website, but uses an adapter to create host-specific files. Defaults to `server` if not specified. ```js title="my-adapter.mjs" ins={9-11} export default function createIntegration() { @@ -914,9 +914,9 @@ A union of valid formats to describe the support level for a feature. Defines the level of support for a feature by your adapter: * Use `"deprecated"` when your adapter deprecates a feature support before removing it completely in a future version. -* Use `"experimental"` when your adapter adds support for a feature and issues or breaking changes are expected. +* Use `"experimental"` when your adapter adds support for a feature, but issues or breaking changes are expected. * Use `"limited"` when your adapter only supports a subset of the full feature. -* Use `"stable"` when the feature is fully supported by your adapter and stable. +* Use `"stable"` when the feature is fully supported by your adapter. * Use `"unsupported"` to warn users that they may encounter build issues in their project, as this feature is not supported by your adapter. ### `AdapterSupportWithMessage` @@ -1008,7 +1008,7 @@ export default function createIntegration() { ## Allow installation via `astro add` -[The `astro add` command](/en/reference/cli-reference/#astro-add) allows users to easily add integrations and adapters to their project. If you want _your_ adapter to be installable with this tool, **add `astro-adapter` to the `keywords` field in your `package.json`**: +[The `astro add` command](/en/reference/cli-reference/#astro-add) allows users to easily add integrations and adapters to their project. To allow your adapter to be installed with this command, **add `astro-adapter` to the `keywords` field in your `package.json`**: ```json { @@ -1017,4 +1017,4 @@ export default function createIntegration() { } ``` -Once you [publish your adapter to npm](https://docs.npmjs.com/cli/v8/commands/npm-publish), running `astro add example` will install your package with any peer dependencies specified in your `package.json`. We will also instruct users to update their project config manually. +Once you [publish your adapter to npm](https://docs.npmjs.com/cli/v8/commands/npm-publish), running `astro add example` will install your package with any peer dependencies specified in your `package.json` and instruct users to update their project config manually. From aad56add7097dcb80c0ce61bd68cff1aadc00135 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 7 Nov 2025 14:28:40 +0100 Subject: [PATCH 17/21] move `experimentalRouteToHeaders` paragraph below code snippet Co-authored-by: Sarah Rainsberger <5098874+sarah11918@users.noreply.github.com> --- src/content/docs/en/reference/adapter-reference.mdx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 78ee7b9dd32de..283aa1cfdd867 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -865,10 +865,6 @@ export default function createIntegration() {

When this feature is enabled, Astro will return a map of the `Headers` emitted by the static pages. This map `experimentalRouteToHeaders` is available in the [`astro:build:generated` hook](/en/reference/integrations-reference/#astrobuildgenerated). - -The value of the headers might change based on the features enabled/used by the application. - -For example, if [CSP is enabled](/en/reference/experimental-flags/csp/), the `` element is not added to the static page. Instead its `content` is available in the `experimentalRouteToHeaders` map. ```js title="my-adapter.mjs" ins={9-11} export default function createIntegration() { @@ -893,6 +889,8 @@ export default function createIntegration() { } ``` +The value of the headers might change based on the features enabled/used by the application. For example, if [CSP is enabled](/en/reference/experimental-flags/csp/), the `` element is not added to the static page. Instead its `content` is available in the `experimentalRouteToHeaders` map. + ## Adapter types reference ### `AdapterSupport` From 10285f94aa8e3c157a37f7ebe10d7ccedd357180 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 7 Nov 2025 14:31:51 +0100 Subject: [PATCH 18/21] reword `adapterFeatures` and remove read more Co-authored-by: Sarah Rainsberger <5098874+sarah11918@users.noreply.github.com> --- src/content/docs/en/reference/adapter-reference.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 283aa1cfdd867..3b5696929dd11 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -84,9 +84,7 @@ A map of Astro built-in features supported by the adapter. This allows Astro to

-An object that enables specific features that must be supported by the adapter. These features will change the built output, and the adapter must implement the proper logic to handle the different output. - -Learn more about the [available features](#adapter-features) that an adapter can activate. +An object that specifies which [adapter features that change the build output](#adapter-features) are supported by the adapter. ### `args` From 0ae487f482de690e1a9f10322266f557d5334fbb Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger <5098874+sarah11918@users.noreply.github.com> Date: Fri, 7 Nov 2025 10:08:39 -0400 Subject: [PATCH 19/21] we don't say SSR anymore! Co-authored-by: Armand Philippot --- src/content/docs/en/reference/adapter-reference.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index 3b5696929dd11..d48356c2eebb9 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -537,7 +537,7 @@ try {

-Returns a list of permitted host patterns for incoming requests when using SSR [as defined in the user configuration](/en/reference/configuration-reference/#securityalloweddomains). +Returns a list of permitted host patterns for incoming requests when using on-demand rendering [as defined in the user configuration](/en/reference/configuration-reference/#securityalloweddomains). #### `app.removeBase()` From 17f719a535ad72372e167bec50858b98f70cf493 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 7 Nov 2025 17:27:29 +0100 Subject: [PATCH 20/21] add a `astro/app/node` section --- .../docs/en/reference/adapter-reference.mdx | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index d48356c2eebb9..bc022b6191bac 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -569,6 +569,90 @@ if (app.setCookieHeaders) { } ``` +### `astro/app/node` + +Just like [`astro/app`](#astroapp), this module is used for rendering pages that have been prebuilt through `astro build`. This allows you to create a `NodeApp` providing all the methods available from `App` and additional methods useful for Node environments. + +The `NodeApp` constructor accepts a required SSR manifest argument, and optionally an argument to enable or disable streaming, defaulting to `true`. + +```js +import { NodeApp } from 'astro/app/node'; +import http from 'http'; + +export function start(manifest) { + const nodeApp = new NodeApp(manifest); + + addEventListener('fetch', event => { + event.respondWith( + nodeApp.render(event.request) + ); + }); +} +``` + +The following additional methods are provided: + +#### `nodeApp.render()` + +

+ +**Type:** `(request: NodeRequest | Request, options?: RenderOptions) => Promise`
+ +

+ +Extends [`app.render()`](#apprender) to also accept [Node.js `IncomingMessage`](https://nodejs.org/api/http.html#class-httpincomingmessage) objects in addition to standard `Request` objects as first argument. The second argument is an optional object allowing you to [control the rendering](#renderoptions). + +```js +const response = await nodeApp.render(request); +``` + +#### `nodeApp.match()` + +

+ +**Type:** `(req: NodeRequest | Request, allowPrerenderedRoutes?: boolean) => RouteData | undefined` +

+ +Extends [`app.match()`](#appmatch) to also accept [Node.js `IncomingMessage`](https://nodejs.org/api/http.html#class-httpincomingmessage) objects in addition to standard `Request` objects. + +```js +if(nodeApp.match(request)) { + const response = await nodeApp.render(request); +} +``` + +#### `nodeApp.headersMap` + +

+ +**Type:** `NodeAppHeadersJson | undefined`
+**Default:** `undefined`
+ +

+ +An array containing headers configuration. Each entry maps a pathname to a list of headers that should be applied for that route. This is useful for applying headers such as CSP directives to prerendered routes. + +#### `nodeApp.setHeadersMap()` + +

+ +**Type:** `(headers: NodeAppHeadersJson) => void`
+ +

+ +Loads [headers configuration](#nodeappheadersmap) into the `NodeApp` instance. + +```js +nodeApp.setHeadersMap([ + { + pathname: "/blog", + headers: [ + { key: "Content-Security-Policy", value: "default-src 'self'" }, + ] + } +]); +``` + ## Astro features Astro features are a way for an adapter to tell Astro whether they are able to support a feature, and also the adapter’s level of support. From 4326cbc051ec65f7f68db5e64312fb576ac634eb Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Mon, 10 Nov 2025 16:35:00 +0100 Subject: [PATCH 21/21] Update src/content/docs/en/reference/adapter-reference.mdx Co-authored-by: Armand Philippot --- src/content/docs/en/reference/adapter-reference.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx index bc022b6191bac..173cd2670e6c5 100644 --- a/src/content/docs/en/reference/adapter-reference.mdx +++ b/src/content/docs/en/reference/adapter-reference.mdx @@ -294,7 +294,7 @@ export default function createIntegration() { } ``` -The second argument passed to `createExports()` can be useful when you need to access build-time configuration in your server entrypoint. For example, your server entrypoint might need the directory path in the build output where the resources generated by Astro are located: +You can access the [`args`](#args) defined by your adapter through the second argument of `createExports()`. This can be useful when you need to access build-time configuration in your server entrypoint. For example, your server might need to identify where assets generated by Astro are located: ```js title="my-adapter/server.js" {4} "args" import { App } from 'astro/app';