Use Advanced Routing
Advanced routing lets you own Astro’s request pipeline from src/fetch.ts.
Use it only when middleware is not enough.
Wrap The Default Pipeline
This is the least invasive pattern. You run code before or after Astro’s built-in pipeline.
import { FetchState, astro } from 'astro/fetch';
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname.startsWith('/api/external')) {
return fetch(new URL(url.pathname, 'https://api.example.com'));
}
const state = new FetchState(request);
const response = await astro(state);
response.headers.set('X-App', 'astro');
return response;
},
};
Change The Entrypoint Name
If src/fetch.ts already exists for another purpose, use fetchFile:
import { defineConfig } from 'astro/config';
export default defineConfig({
fetchFile: 'handler',
});
Astro will look for src/handler.ts instead.
Disable entrypoint detection entirely when you do not need it:
import { defineConfig } from 'astro/config';
export default defineConfig({
fetchFile: null,
});
Compose With Hono
Use Hono when you already want Hono middleware or route grouping:
import { Hono } from 'hono';
import { logger } from 'hono/logger';
import { actions, middleware, pages, i18n } from 'astro/hono';
const app = new Hono();
app.use(logger());
app.use(actions());
app.use(middleware());
app.use(pages());
app.use(i18n());
export default app;
Keep The Pipeline Complete
When composing individual handlers, you become responsible for order. If you omit sessions(), actions(), i18n(), or cache(), those features do not magically run later.
Gotcha: Advanced routing is stable, but it is also an escape hatch. The more of Astro’s pipeline you recompose manually, the more framework behavior you own.