Where we started
Our old site was on a popular page-builder CMS — the kind that makes the first deploy easy and the hundredth painful. By year three we were spending two hours a week fighting it. The page-builder couldn’t do flex layouts the way we needed. Every plugin update broke at least one component. Page speeds were dropping into the red on Lighthouse.
What we wanted
Three things, in order:
- Faster. LCP under 1s on slow networks. No render-blocking ads. No JS bundles for pages that don’t need them.
- Edit-without-fear. A site that we could change without praying the page builder didn’t eat our work.
- Type-safe. Everything in TypeScript so a missing prop is caught at build time, not in production.
Astro hit all three.
What we built
- Eleven pages, content collections for projects and blog posts
- One config file (
src/config/site.ts) that owns everything: nav links, footer columns, services, team, FAQs - A handful of components per page, all server-rendered, with zero client JS where we could avoid it
- GSAP ScrollTrigger for the stacking case-study deck on the homepage (the only place we couldn’t avoid client JS)
What broke
The migration script for our old blog posts hallucinated three image paths. We didn’t catch it for two weeks because Lighthouse doesn’t flag 404 images on lazy-loaded content. Build-time link validation is now part of our CI.
What we’d do differently
Less custom CSS, more Tailwind utilities. We started with a heavy global.css and kept reaching back into it. By month two, every component had its own scoped styles and the global file was 60% smaller. If we did it again, we’d start that way.
The numbers
Median LCP went from 3.8s to 0.6s. Bundle size dropped 89%. Editorial cycle time (write → review → publish) went from 25 minutes to under 5. The bill at our previous host went from £140/month to £0 on Cloudflare Pages.