Skip to content

Frontend framework: Astro

  • Status: Accepted
  • Date: 2026-06-06
  • Deciders: Engineering, Design Systems

quarry.team is a content-and-craft marketing site: a homepage, services, a curated case-study library (/work/<slug>), an editorial blog (/blog/<slug>), an about/team section, and lead-capture forms (contact, careers). The dominant requirements are:

  • Best-in-class Core Web Vitals. The site is itself an argument for our engineering taste; near-zero unused JavaScript on content pages is the target (see docs/brd/non-functional-requirements.md).
  • Content-first authoring via typed, git-based collections (MDX + Zod) — see ADR 0004.
  • A real design system sourced from design tokens — see ADR 0003 and ADR 0007.
  • Static output deployed to Cloudflare’s edge — see ADR 0006.
  • Islands of interactivity where genuinely needed (mobile nav, lightweight form widgets, search UI) without shipping a SPA runtime to every visitor.

The legacy site is Gridsome (Vue 2). Gridsome is effectively unmaintained, Vue 2 is end-of-life, and the architecture couples content to a WordPress instance we want to retire.

We will build the marketing site (apps/web) on Astro with TypeScript in strict mode (Astro 5 at the time of this decision; the project tracks the current major and now runs on Astro 7 — routine version currency, not a change of framework).

Rationale:

  • Zero-JS by default, islands on demand. Astro ships HTML/CSS and hydrates only the components we explicitly mark, which maps directly onto our CWV budget. Most pages ship no framework runtime at all.
  • First-class content layer. Astro Content Collections give us typed MDX + Zod schemas out of the box — the exact content model we want (ADR 0004) — with no separate CMS to run.
  • Static-first, edge-friendly. Pages prerender to static HTML, deployed as a single Cloudflare Worker via the @astrojs/cloudflare adapter (ADR 0006); the only on-demand routes are the same-origin /api/* form endpoints. @astrojs/sitemap and Pagefind fit cleanly.
  • Framework-agnostic islands. If we ever need a React/Svelte/Vue island, Astro supports it without committing the whole site to one runtime.
  • Authoring ergonomics. .astro components are close to HTML, which keeps the markup honest and the design-token mapping legible.

Positive

  • Content pages ship essentially no JavaScript; CWV headroom is large.
  • The content model, framework, and search are one coherent toolchain.
  • TypeScript strict + astro check catches content-schema and template errors at build time.

Negative / costs

  • Astro’s island model is a different mental model than an SPA; complex client-side state is deliberately awkward (acceptable — this is a marketing site, and the controlled dynamic tier is just the same-origin /api/* form routes on the Worker, backed by D1, ADR 0014).
  • Smaller ecosystem than Next.js for app-style features we don’t need here.
  • Next.js. Excellent, but optimized for app-shaped React products. Reaching the same “no unused JS on a content page” baseline requires fighting the defaults (RSC payloads, hydration). Heavier than the problem.
  • Remix / React Router. Server-rendering-first; great for dynamic apps, but we want static output and minimal client JS. Wrong center of gravity.
  • SvelteKit. Closest competitor on the “lean output” axis and genuinely good. Astro wins on the content-collection story and the explicit islands-everywhere-else model for a multi-framework-tolerant marketing site.
  • Keep Gridsome (Vue 2). Unmaintained, EOL runtime, coupled to WordPress. Non-starter.