Skip to main content
Astro Integrations add new functionality and behaviors for your project with just a few lines of code. This page describes the API for building your own integrations.

Integration Structure

An Astro integration is an object with a name and hooks property:
export interface AstroIntegration {
  name: string;
  hooks: IntegrationHooks;
}

Basic Example

function myIntegration() {
  return {
    name: 'my-integration',
    hooks: {
      'astro:config:setup': ({ config, command, updateConfig }) => {
        // Run during setup
      },
      'astro:build:done': ({ dir, pages }) => {
        // Run after build
      }
    }
  };
}

Integration Hooks

Integrations can define hook functions that run at specific times during Astro’s lifecycle. All hooks are optional.

astro:config:setup

hooks['astro:config:setup']
function
Called during Astro initialization, before the Vite or Astro config have been resolved. This hook can be used to extend project configuration.Parameters:
  • config - A read-only copy of the user-supplied Astro config
  • command - The command used to run Astro: 'dev', 'build', 'preview', or 'sync'
  • isRestart - Whether the dev server is restarting
  • updateConfig - Function to update the user config
  • addRenderer - Add a framework renderer (React, Vue, etc.)
  • addWatchFile - Add a file to watch for changes
  • injectScript - Inject a client script into pages
  • injectRoute - Add a new route to the Astro project
  • addClientDirective - Add a custom client directive
  • addDevToolbarApp - Add a custom dev toolbar app
  • addMiddleware - Add middleware
  • createCodegenDir - Create a directory for generated code
  • logger - Integration logger instance
'astro:config:setup': ({ updateConfig, addRenderer, injectScript }) => {
  // Update config
  updateConfig({
    vite: {
      plugins: [myVitePlugin()]
    }
  });

  // Add a framework renderer
  addRenderer({
    name: '@astrojs/react',
    serverEntrypoint: '@astrojs/react/server.js'
  });

  // Inject a script
  injectScript('page', 'console.log("Hello from my integration!");');
}

astro:config:done

hooks['astro:config:done']
function
Called after the Astro config has been fully resolved and other integrations have run their astro:config:setup hooks.Parameters:
  • config - The resolved Astro config
  • setAdapter - Set the adapter for SSR
  • injectTypes - Inject TypeScript type definitions
  • logger - Integration logger instance
  • buildOutput - The build output mode: 'static' or 'server'
'astro:config:done': ({ config, setAdapter, injectTypes }) => {
  // Set an adapter
  setAdapter({
    name: 'my-adapter',
    serverEntrypoint: './server.js',
    supportedAstroFeatures: {
      staticOutput: 'stable',
      serverOutput: 'stable'
    }
  });

  // Inject types
  const typesPath = injectTypes({
    filename: 'types.d.ts',
    content: 'declare module "my-integration" { }'
  });
}

astro:server:setup

hooks['astro:server:setup']
function
Called during the dev server setup, before the server starts. Allows access to the Vite dev server instance.Parameters:
  • server - The Vite dev server instance
  • logger - Integration logger instance
  • toolbar - Dev toolbar communication helpers
  • refreshContent - Function to refresh content collections (optional)
'astro:server:setup': ({ server }) => {
  server.middlewares.use((req, res, next) => {
    // Add custom middleware
    next();
  });
}

astro:server:start

hooks['astro:server:start']
function
Called after the dev server has started.Parameters:
  • address - The server address information (host, port, etc.)
  • logger - Integration logger instance
'astro:server:start': ({ address }) => {
  console.log(`Server running at http://${address.address}:${address.port}`);
}

astro:server:done

hooks['astro:server:done']
function
Called when the dev server is closed.Parameters:
  • logger - Integration logger instance
'astro:server:done': () => {
  console.log('Dev server closed');
}

astro:build:start

hooks['astro:build:start']
function
Called when the build process starts.Parameters:
  • logger - Integration logger instance
  • setPrerenderer - Set a custom prerenderer (advanced)
'astro:build:start': () => {
  console.log('Build starting...');
}

astro:build:setup

hooks['astro:build:setup']
function
Called during the build, allows you to extend the Vite configuration used during the build.Parameters:
  • vite - Vite config for the build
  • pages - Map of page paths to their build data
  • target - Build target: 'client' or 'server'
  • updateConfig - Function to update the Vite config
  • logger - Integration logger instance
'astro:build:setup': ({ vite, target, updateConfig }) => {
  if (target === 'client') {
    updateConfig({
      build: {
        rollupOptions: {
          output: { manualChunks: {} }
        }
      }
    });
  }
}

astro:build:generated

hooks['astro:build:generated']
function
Called after a static build has generated all routes and assets.Parameters:
  • dir - The build output directory
  • logger - Integration logger instance
  • routeToHeaders - Map of routes to their HTTP headers (when adapter supports static headers)
'astro:build:generated': ({ dir }) => {
  // Generate additional files in the output directory
  console.log(`Build output: ${dir.pathname}`);
}

astro:build:ssr

hooks['astro:build:ssr']
function
Called after an SSR build has completed.Parameters:
  • manifest - The serialized SSR manifest
  • middlewareEntryPoint - File path of the emitted middleware
  • logger - Integration logger instance
'astro:build:ssr': ({ manifest, middlewareEntryPoint }) => {
  // Process SSR build output
}

astro:build:done

hooks['astro:build:done']
function
Called after the build has completed and all output files have been written to disk.Parameters:
  • pages - Array of all generated pages with pathname info
  • dir - The build output directory
  • assets - Map of asset file names to their output URLs
  • logger - Integration logger instance
'astro:build:done': ({ pages, dir, assets }) => {
  console.log(`Built ${pages.length} pages to ${dir.pathname}`);
}

astro:route:setup

hooks['astro:route:setup']
function
Called for each route during routing setup. Allows you to modify route options.Parameters:
  • route - Route options including component path and prerender setting
  • logger - Integration logger instance
'astro:route:setup': ({ route }) => {
  // Modify route prerender behavior
  if (route.component.includes('blog')) {
    route.prerender = true;
  }
}

astro:routes:resolved

hooks['astro:routes:resolved']
function
Called after all routes have been resolved.Parameters:
  • routes - Array of all resolved routes in the project
  • logger - Integration logger instance
'astro:routes:resolved': ({ routes }) => {
  console.log(`Found ${routes.length} routes`);
}

Adding Framework Renderers

Use the addRenderer function in the astro:config:setup hook to add support for UI frameworks:
addRenderer({
  name: '@astrojs/react',
  clientEntrypoint: '@astrojs/react/client.js',
  serverEntrypoint: '@astrojs/react/server.js'
});

Injecting Scripts

Use the injectScript function to add JavaScript to pages:
injectScript('page', `
  console.log('This runs on every page!');
`);
Script stages:
  • 'before-hydration' - Imported client-side, before hydration
  • 'head-inline' - Injected into a script tag in the <head>
  • 'page' - Injected into the JavaScript bundle of every page
  • 'page-ssr' - Injected into the frontmatter of every Astro page

Adding Routes

Use the injectRoute function to add new routes:
injectRoute({
  pattern: '/custom-route',
  entrypoint: './src/custom-route.astro'
});

Adding Middleware

Use the addMiddleware function to add middleware:
addMiddleware({
  entrypoint: './src/middleware.ts',
  order: 'pre' // or 'post'
});

Client Directives

Add custom client directives for controlling component hydration:
addClientDirective({
  name: 'my-directive',
  entrypoint: './directives/my-directive.js'
});

Dev Toolbar Apps

Add custom apps to the Astro dev toolbar:
addDevToolbarApp({
  id: 'my-toolbar-app',
  name: 'My App',
  icon: '<svg>...</svg>',
  entrypoint: './toolbar-app.js'
});

TypeScript Types

Inject TypeScript type definitions into the user’s project:
'astro:config:done': ({ injectTypes }) => {
  injectTypes({
    filename: 'types.d.ts',
    content: `declare module 'my-integration' {
      export function myFunction(): void;
    }`
  });
}

Integration Logger

All hooks receive a logger instance for consistent logging:
'astro:config:setup': ({ logger }) => {
  logger.info('Setting up integration');
  logger.warn('This is a warning');
  logger.error('This is an error');
}

Building Adapters

Adapters are a special type of integration that set the adapter configuration. Use the setAdapter function in astro:config:done:
'astro:config:done': ({ setAdapter }) => {
  setAdapter({
    name: 'my-adapter',
    serverEntrypoint: './server.js',
    previewEntrypoint: './preview.js',
    supportedAstroFeatures: {
      staticOutput: 'stable',
      serverOutput: 'stable',
      hybridOutput: 'stable',
      i18nDomains: 'stable',
      envGetSecret: 'experimental'
    },
    adapterFeatures: {
      buildOutput: 'server',
      staticHeaders: true
    }
  });
}

Adapter Features

supportedAstroFeatures

Defines which Astro features the adapter supports:
  • staticOutput - Serving static pages
  • serverOutput - On-demand rendered pages
  • hybridOutput - Mix of static and on-demand pages
  • i18nDomains - i18n domain routing
  • envGetSecret - Retrieving secrets from astro:env/server
  • sharpImageService - Image transformation with Sharp
Each feature can be:
  • 'stable' - Fully supported
  • 'experimental' - Experimental support
  • 'deprecated' - Deprecated support
  • 'unsupported' - Not supported
  • { support: 'limited', message: 'Custom message' } - Limited support with explanation

adapterFeatures

Controls adapter-specific build features:
  • buildOutput - Force 'static' or 'server' output
  • middlewareMode - 'classic' or 'edge' middleware execution
  • staticHeaders - Support for setting headers on static pages

Complete Integration Example

import { fileURLToPath } from 'node:url';

export default function myIntegration(options = {}) {
  return {
    name: 'my-integration',
    hooks: {
      'astro:config:setup': ({ 
        config, 
        command, 
        updateConfig, 
        addRenderer, 
        injectScript,
        logger 
      }) => {
        logger.info('Setting up integration');

        // Add framework support
        addRenderer({
          name: '@my/renderer',
          serverEntrypoint: '@my/renderer/server'
        });

        // Update Vite config
        updateConfig({
          vite: {
            plugins: [/* ... */]
          }
        });

        // Inject client script
        if (command === 'dev') {
          injectScript('page', 'console.log("Dev mode")');
        }
      },
      'astro:config:done': ({ config, logger }) => {
        logger.info(`Config resolved for ${config.site}`);
      },
      'astro:build:done': ({ dir, pages, logger }) => {
        logger.info(`Built ${pages.length} pages to ${dir.pathname}`);
      }
    }
  };
}

Build docs developers (and LLMs) love