This episode covers Astro extensibility: writing custom integrations and plugins, using third-party libraries and frameworks, extending the build pipeline with custom scripts, and interoperability across the frontend ecosystem.

Every framework has limits, and what distinguishes a great framework is how easy it is to extend those limits. Episode 18 covers Astro extensibility: writing custom integrations, using third-party libraries, extending the build pipeline, and connecting different frontend ecosystems.
You will learn that Astro integrations are not magic — they are plain JavaScript objects with hooks that run at specific moments in the build lifecycle. Understanding this opens the door to automating much of what you previously did by hand.
By the end of the episode, you can write your own integrations and hook any tool into an Astro project.
An Astro integration is an object with hooks functions called at specific times: astro:config:setup, astro:config:done, and astro:build:done. Example of a simple integration that injects a script into every page:
import type { AstroIntegration } from "astro";
export function sapaPengunjung(): AstroIntegration {
return {
name: "sapa-pengunjung",
hooks: {
"astro:config:done": ({ injectScript }) => {
injectScript(
"page",
`console.log("Selamat datang di situs ini!");`,
);
},
},
};
}The injectScript("page", ...) function injects code into the page. This integration just needs to be added to the integrations array in astro.config.mjs to become active.
Write a custom integration when the need is recurring and reusable across many projects: adding automatic meta tags, transforming build output, or integrating an analytics service. For one-off needs, a plain script is enough.
Plain JavaScript libraries can be used directly in frontmatter or in src/lib. Because Astro uses Vite, almost any browser-compatible npm package works without configuration:
npm install date-fnsThen use it in a page:
---
import { format } from "date-fns";
import { id } from "date-fns/locale";
const tanggal = format(new Date(), "d MMMM yyyy", { locale: id });
---
<p>Hari ini: {tanggal}</p>format(new Date(), "d MMMM yyyy", { locale: id }) uses date-fns to format the date in Indonesian — everything runs at build time.
The React, Vue, Svelte, and Solid integrations (episode 7) are the prime examples of interoperability. You can also load UI components from any design system as long as they are converted or wrapped into a supported form.
Custom scripts are added to package.json and can be chained with the build command:
{
"scripts": {
"build": "astro build && node scripts/gen-sitemap-ekstra.mjs",
"prerender": "node scripts/prerender.mjs"
}
}The command astro build && node scripts/gen-sitemap-ekstra.mjs runs the build then produces an extra file. This approach is flexible for needs that integrations do not handle.
For full access to the build result, use the astro:build:done hook inside an integration. This hook receives the list of generated pages — perfect for reports, validation, or output transformation:
"astro:build:done": ({ pages }) => {
console.log(`Total halaman yang dibangun: ${pages.length}`);
}pages contains all generated routes. You can write a build summary to a file or validate that important pages actually exist.
A frequently underestimated Astro strength: different frontend teams can live in one project. Team A uses React for the dashboard, team B uses Svelte for widgets — both are rendered by Astro with separate hydration.
So integrations do not turn into spaghetti:
src/components/react and src/components/svelte.Interoperability is a strength, but clear boundaries keep it maintainable.
Tip
Before writing your own integration, check npm first — @astrojs/* and community packages may already provide what you need. Write custom code only for needs with no existing solution.
Episode 18 opens up Astro extensibility: writing custom integrations with hooks like injectScript and astro:build:done, using npm libraries directly, extending the build pipeline with custom scripts, and maintaining cross-framework interoperability.
The key takeaways:
injectScript injects code into pages from an integration.&& in package.json.astro:build:done gives access to the build result.In the next episode 19, we will cover modern tooling and build automation: the Astro CLI and Vite, TypeScript integration with strict typing, CI/CD pipelines for Astro projects, and linting, formatting, and pre-commit hooks. Your quality will be maintained automatically.