Astro Integration API
Astro Integrations add new functionality and behaviors for your project with only a few lines of code.
This reference page is for anyone writing their own integration. To learn how to use an integration in your project, check out our Using Integrations guide instead.
Examples
Section titled ExamplesThe official Astro integrations can act as reference for you as you go to build your own integrations.
Quick API Reference
Section titled Quick API Referenceinterface AstroIntegration {
name: string;
hooks: {
'astro:config:setup'?: (options: {
config: AstroConfig;
command: 'dev' | 'build';
updateConfig: (newConfig: Record<string, any>) => void;
addRenderer: (renderer: AstroRenderer) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: ({ pattern: string, entryPoint: string }) => void;
}) => void;
'astro:config:done'?: (options: { config: AstroConfig }) => void | Promise<void>;
'astro:server:setup'?: (options: { server: vite.ViteDevServer }) => void | Promise<void>;
'astro:server:start'?: (options: { address: AddressInfo }) => void | Promise<void>;
'astro:server:done'?: () => void | Promise<void>;
'astro:build:start'?: (options: { buildConfig: BuildConfig }) => void | Promise<void>;
'astro:build:setup'?: (options: {
vite: ViteConfigWithSSR;
pages: Map<string, PageBuildData>;
target: 'client' | 'server';
}) => void | Promise<void>;
'astro:build:generated'?: (options: { dir: URL }) => void | Promise<void>;
'astro:build:ssr'?: (options: { manifest: SerializedSSRManifest }) => void | Promise<void>;
'astro:build:done'?: (options: { dir: URL; routes: RouteData[] }) => void | Promise<void>;
};
}
Hooks
Section titled Hooksastro:config:setup
Section titled astro:config:setupNext hook: astro:config:done
When: On initialization, before either the Vite or Astro config have resolved.
Why: To extend the project config. This inludes updating the Astro config, applying Vite plugins, adding component renderers, and injecting scripts onto the page.
'astro:config:setup'?: (options: {
config: AstroConfig;
command: 'dev' | 'build';
isRestart: boolean;
updateConfig: (newConfig: Record<string, any>) => void;
addRenderer: (renderer: AstroRenderer) => void;
addWatchFile: (path: URL | string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: ({ pattern: string, entryPoint: string }) => void;
}) => void;
config
option
Section titled config optionType: AstroConfig
A read-only copy of the user-supplied Astro config. This is resolved before any other integrations have run. If you need a copy of the config after all integrations have completed their config updates, see the astro:config:done
hook.
command
option
Section titled command optionType: 'dev' / 'build'
dev
- Project is executed withastro dev
orastro preview
build
- Project is executed withastro build
isRestart
option
Section titled isRestart optionType: boolean
false
when the dev server starts, true
when a reload is triggered. Useful to detect when this function is called more than once.
updateConfig
option
Section titled updateConfig optionType: (newConfig: Record<string, any>) => void;
A callback function to update the user-supplied Astro config. Any config you provide will be merged with the user config + other integration config updates, so you are free to omit keys!
For example, say you need to supply a Vite plugin to the user’s project:
import bananaCSS from '@vitejs/official-banana-css-plugin';
export default {
name: 'banana-css-integration',
hooks: {
'astro:config:setup': ({ updateConfig }) => {
updateConfig({
vite: {
plugins: [bananaCSS()],
}
})
}
}
}
addRenderer
option
Section titled addRenderer optionType: (renderer:
AstroRenderer
) => void;
Examples: lit
, svelte
, react
, preact
, vue
, solid
A callback function to add a component framework renderer (i.e. React, Vue, Svelte, etc). You can browse the examples and type definition above for more advanced options, but here are the 2 main options to be aware of:
clientEntrypoint
- path to a file that executes on the client whenever your component is used. This is mainly for rendering or hydrating your component with JS.serverEntrypoint
- path to a file that executes during server-side requests or static builds whenever your component is used. These should render components to static markup, with hooks for hydration where applicable. React’srenderToString
callback is a classic example.
addWatchFile
option
Section titled addWatchFile optionType: URL | string
If your integration depends on some configuration file that Vite doesn’t watch and/or needs a full dev server restart to take effect, add it with addWatchFile
. Whenever that file changes, the Astro dev server will be reloaded (you can check when a reload happens with isRestart
).
Example usage:
// Must be an absolute path!
addWatchFile('/home/user/.../my-config.json');
addWatchFile(new URL('./tailwind.config.js', config.root));
injectRoute
option
Section titled injectRoute optionType: ({ pattern: string, entryPoint: string }) => void;
A callback function to inject routes into an Astro project. Injected routes can be .astro
pages or .js
and .ts
route handlers.
injectRoute
takes an object with a pattern
and an entryPoint
.
pattern
- where the route should be output in the browser, for example/foo/bar
. Apattern
can use Astro’s filepath syntax for denoting dynamic routes, for example/foo/[bar]
or/foo/[...bar]
. Note that a file extension is not needed in thepattern
.entryPoint
- a bare module specifier pointing towards the.astro
page or.js
/.ts
route handler that handles the route denoted in thepattern
.
Example usage:
injectRoute({
pattern: '/foo/[dynamic]',
entryPoint: 'foo/dynamic-page.astro'
});
injectScript
option
Section titled injectScript optionType: (stage: InjectedScriptStage, content: string) => void;
A callback function to inject a string of JavaScript content onto every page.
The stage
denotes how this script (the content
) should be inserted. Some stages allow inserting scripts without modification, while others allow optimization during Vite’s bundling step:
-
"head-inline"
: Injected into a script tag in the<head>
of every page. Not optimized or resolved by Vite. -
"before-hydration"
: Imported client-side, before the hydration script runs. Optimized and resolved by Vite. -
"page"
: Similar tohead-inline
, except that the injected snippet is handled by Vite and bundled with any other<script>
tags defined inside of Astro components on the page. The script will be loaded with a<script type="module">
in the final page output, optimized and resolved by Vite. -
"page-ssr"
: Imported as a separate module in the frontmatter of every Astro page component. Because this stage imports your script, theAstro
global is not available and your script will only be run once when theimport
is first evaluated.The main use for the
page-ssr
stage is injecting a CSSimport
into every page to be optimized and resolved by Vite:injectScript('page-ssr', 'import "global-styles.css";');
astro:config:done
Section titled astro:config:donePrevious hook: astro:config:setup
Next hook: astro:server:setup
when running in “dev” or “preview” mode, or astro:build:start
during production builds
When: After the Astro config has resolved and other integrations have run their astro:config:setup
hooks.
Why: To retrieve the final config for use in other hooks.
'astro:config:done'?: (options: { config: AstroConfig }) => void | Promise<void>;
config
option
Section titled config optionType: AstroConfig
A read-only copy of the user-supplied Astro config. This is resolved after other integrations have run.
astro:server:setup
Section titled astro:server:setupPrevious hook: astro:config:done
Next hook: astro:server:start
When: Just after the Vite server is created in “dev” or “preview” mode, but before the listen()
event is fired. See Vite’s createServer API for more.
Why: To update Vite server options and middleware.
'astro:server:setup'?: (options: { server: vite.ViteDevServer }) => void | Promise<void>;
server
option
Section titled server optionType: ViteDevServer
A mutable instance of the Vite server used in “dev” and “preview” mode. For instance, this is used by our Partytown integration to inject the Partytown server as middleware:
export default {
name: 'partytown',
hooks: {
'astro:server:setup': ({ server }) => {
server.middlewares.use(
function middleware(req, res, next) {
// handle requests
}
);
}
}
}
astro:server:start
Section titled astro:server:startPrevious hook: astro:server:setup
Next hook: astro:server:done
When: Just after the server’s listen()
event has fired.
Why: To intercept network requests at the specified address. If you intend to use this address for middleware, consider using astro:server:setup
instead.
'astro:server:start'?: (options: { address: AddressInfo }) => void | Promise<void>;
address
option
Section titled address optionType: AddressInfo
The address, family and port number supplied by the NodeJS Net module.
astro:server:done
Section titled astro:server:donePrevious hook: astro:server:start
When: Just after the dev server is closed.
Why: To run any cleanup events you may trigger during the astro:server:setup
or astro:server:start
hooks.
'astro:server:done'?: () => void | Promise<void>;
astro:build:start
Section titled astro:build:startPrevious hook: astro:config:done
Next hook: astro:build:setup
When: After the astro:config:done
event, but before the production build begins.
Why: To set up any global objects or clients needed during a production build. This can also extend the build configuration options in the adapter API.
'astro:build:start'?: (options: { buildConfig: BuildConfig }) => void | Promise<void>;
astro:build:setup
Section titled astro:build:setupPrevious hook: astro:build:start
Next hook: astro:build:ssr
When: After the astro:build:start
hook, runs immediately before the build.
Why: At this point, the Vite config for the build has been completely constructed, this is your final chance to modify it. This can be useful for example to overwrite some defaults. If you’re not sure whether you should use this hook or astro:build:start
, use astro:build:start
instead.
'astro:build:setup'?: (options: {
vite: ViteConfigWithSSR;
pages: Map<string, PageBuildData>;
target: 'client' | 'server';
}) => void | Promise<void>;
astro:build:generated
Section titled astro:build:generatedPrevious hook: astro:build:setup
When: After a static production build has finished generating routes and assets.
Why: To access generated routes and assets before build artifacts are cleaned up. This is a very uncommon use case. We recommend using astro:build:done
unless you really need to access the generated files before cleanup.
'astro:build:generated'?: (options: { dir: URL }) => void | Promise<void>;
astro:build:ssr
Section titled astro:build:ssrPrevious hook: astro:build:setup
When: After a production SSR build has completed.
Why: To get access the SSR manifest, this is useful when creating custom SSR builds in plugins or integrations.
'astro:build:ssr'?: (options: { manifest: SerializedSSRManifest }) => void | Promise<void>;
astro:build:done
Section titled astro:build:donePrevious hook: astro:build:ssr
When: After a production build (SSG or SSR) has completed.
Why: To access generated routes and assets for extension (ex. copy content into the generated /assets
directory). If you plan to transform generated assets, we recommend exploring the Vite Plugin API and configuring via astro:config:setup
instead.
'astro:build:done'?: (options: { dir: URL; routes: RouteData[] }) => void | Promise<void>;
dir
option
Section titled dir optionType: URL
A URL path to the build output directory. Note that if you need a valid absolute path string, you should use Node’s built-in fileURLToPath
utility.
import { writeFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
export default function myIntegration() {
return {
hooks: {
'astro:build:done': async ({ dir }) => {
const metadata = await getIntegrationMetadata();
// Use fileURLToPath to get a valid, cross-platform absolute path string
const outFile = fileURLToPath(new URL('./my-integration.json', dir));
await writeFile(outFile, JSON.stringify(metadata));
}
}
}
}
routes
option
Section titled routes optionType: RouteData[]
A list of all generated routes alongside their associated metadata. This will be empty when using an SSR adapter!
You can reference the full RouteData
type below, but the most common properties are:
component
- the input file path relative to the project rootpathname
- the output file URL (undefined for routes using[dynamic]
and[...spread]
params)
RouteData
type reference
interface RouteData {
/** Whether a given route is an HTML page or non-HTML endpoint */
type: 'page' | 'endpoint';
/** Source component URL */
component: string;
/**
* Output URL pathname where this route will be served
* note: will be undefined for [dynamic] and [...spread] routes
*/
pathname?: string;
/**
* regex used for matching an input URL against a requested route
* ex. "[fruit]/about.astro" will generate the pattern: /^\/([^/]+?)\/about\/?$/
* where pattern.test("banana/about") is "true"
*/
pattern: RegExp;
/**
* Dynamic and spread route params
* ex. "/pages/[lang]/[..slug].astro" will output the params ['lang', '...slug']
*/
params: string[];
/**
* Similar to the "params" field, but with more associated metadata
* ex. "/pages/[lang]/index.astro" will output the segments
* [[ { content: 'lang', dynamic: true, spread: false } ]]
*/
segments: { content: string; dynamic: boolean; spread: boolean; }[][];
/**
* Function to render component in-place from a set of input data.
* This is typically for internal use, so call with caution!
*/
generate: (data?: any) => string;
}
Allow installation with astro add
Section titled Allow installation with astro addThe astro add
command allows users to easily add integrations and adapters to their project. If you want your integration to be installable with this tool, add astro-integration
to the keywords
field in your package.json
:
{
"name": "example",
"keywords": ["astro-integration"],
}
Once you publish your integration to npm, running astro add example
will install your package with any peer dependencies specified in your package.json
. This will also apply your integration to the user’s astro.config
like so:
import { defineConfig } from 'astro/config';
+ import example from 'example';
export default defineConfig({
+ integrations: [example()],
})
Integration Ordering
Section titled Integration OrderingAll integrations are run in the order that they are configured. For instance, for the array [react(), svelte()]
in a user’s astro.config.*
, react
will run before svelte
.
Your integration should ideally run in any order. If this isn’t possible, we recommend documenting that your integration needs to come first or last in your user’s integrations
configuration array.
Combine integrations into presets
Section titled Combine integrations into presetsAn integration can also be written as a collection of multiple, smaller integrations. We call these collections presets. Instead of creating a factory function that returns a single integration object, a preset returns an array of integration objects. This is useful for building complex features out of multiple integrations.
integrations: [
// Example: where examplePreset() returns: [integrationOne, integrationTwo, ...etc]
examplePreset()
]