I’ve been building with Astro for a while now, and the same pain points kept showing up across projects. I got tired of patching around them and just built integrations instead.
Three packages. All on npm. All open source.
🎯 What’s an Astro Integration, anyway?
If you’ve never built one — an Astro Integration is a package that hooks into Astro’s build lifecycle or dev toolbar. You return a name and a hooks object, and Astro calls your callbacks at the right moments.
export default function myIntegration(): AstroIntegration {
return {
name: 'my-integration',
hooks: {
'astro:build:done': ({ pages }) => {
// runs after build
}
}
}
}
That’s basically it. It’s how @astrojs/react, Tailwind, Partytown, and most of the ecosystem slot into your config without you wiring anything up yourself.
📦 @shiftescape/astro-bundle-budget
You build your site, ship it, and two weeks later someone notices a page is pulling in 400KB of JS. No warnings. No CI failure. Just a slow page and a mild sense of shame.
This integration hooks into astro:build:done, reads the output, and compares your JS/CSS sizes against budgets you set. Exceed them — build fails.
import bundleBudget from '@shiftescape/astro-bundle-budget';
export default defineConfig({
integrations: [
bundleBudget({
budgets: [
{ type: 'js', budget: 100 }, // 100KB JS max
{ type: 'css', budget: 50 } // 50KB CSS max
]
})
]
});
Set it once, forget about it. The pipeline tells you when something bloats.
🔍 @shiftescape/astro-env-inspector
You’ve got env vars spread across .env, .env.local, .env.production. You’re debugging something weird and you genuinely don’t know which value Astro is actually reading — or if the variable is even loaded at all.
This adds a panel to the Astro Dev Toolbar. All your env vars, grouped, masked by default, searchable. Dev only — nothing touches your production build.
import envInspector from '@shiftescape/astro-env-inspector';
export default defineConfig({
integrations: [envInspector()]
});
Beats staring at console.log(import.meta.env) output and trying to remember which file overrides which.
🗺️ @shiftescape/astro-toolbar-routes
Once a project gets past a dozen pages, you’re either memorizing routes or digging through src/pages/ every time. Neither is fun.
This puts a route map in the dev toolbar — every page in your project, grouped, searchable, clickable. It reads your file-based routes at build time and lists them out.
import toolbarRoutes from '@shiftescape/astro-toolbar-routes';
export default defineConfig({
integrations: [toolbarRoutes()]
});
Click a route, go there. That’s the whole thing.
Using all three together
npm install @shiftescape/astro-bundle-budget @shiftescape/astro-env-inspector @shiftescape/astro-toolbar-routes
// astro.config.mjs
import { defineConfig } from 'astro/config';
import bundleBudget from '@shiftescape/astro-bundle-budget';
import envInspector from '@shiftescape/astro-env-inspector';
import toolbarRoutes from '@shiftescape/astro-toolbar-routes';
export default defineConfig({
integrations: [
bundleBudget({ budgets: [{ type: 'js', budget: 100 }] }),
envInspector(),
toolbarRoutes()
]
});
The toolbar panels are dev-only. The budget check runs at build time and exits non-zero on failure, so CI picks it up without any extra config.
That’s it for now
All three are at v0.1.x — functional and tested, but still early. There’s a lot more I want to do with each of them
If any of these save you some time, a ⭐ on GitHub goes a long way!
Built with the Astro Integration API and listed in the Astro Integrations Library.



