Skip to content

Technology Stack

Framework:
name: Astro
version: {{versions.astro}}
features:
- Static Site Generation (SSG) by default
- Server-Side Rendering (SSR) optional
- Zero JavaScript by default
- Content Layer API (content collections)
- ClientRouter (astro:transitions)
- Server Islands
Build:
bundler: Vite 7.x
runtime: Node.js 24.x (>=24 required)
package_manager: pnpm 10.13.1 (required)
typescript: ^5.9.3
CSS:
framework: Tailwind CSS v4.3.3 (via @tailwindcss/vite plugin)
approach: Utility-first with design tokens, CSS-first configuration
features:
- CSS Variables for theming
- Container queries support
- Built-in dark mode (class-based @variant)
- Oxide engine (no tailwind.config file — configured in CSS via @theme)
Design_Tokens:
format: JSON → CSS variables (tokens/dist/tokens.css), mapped to utilities via @theme inline
build: pnpm run tokens:build (scripts/src/build-tokens.ts)
tools:
- style-dictionary (optional token generation)
- tailwindcss-themer (optional theme switching)
Content:
format: MDX with Astro Content Collections
features:
- Type-safe frontmatter
- Custom components in content
- Automatic image optimization
- Content Layer API for external data
Assets:
images:
- Astro <Image> component
- Sharp for processing
- AVIF + WebP output
fonts:
- Astro Fonts API with fontProviders.local() (self-hosted woff2 in src/assets/fonts/)
- Variable fonts preferred, metric-adjusted fallbacks generated automatically
Progressive_Enhancement:
1. CSS-only solutions (preferred)
2. ClientRouter from astro:transitions (SPA-like navigation)
3. Preact Islands (client-side state)
ClientRouter_vs_Islands:
ClientRouter: For page-level animations and maintaining state across navigation (e.g., persistent audio player). Manages the "frame" of the app.
Islands: For component-level interactivity that requires client-side JavaScript (e.g., an interactive form). Manages interactive "widgets" on a page.
Island_Directives:
- client:visible (lazy load)
- client:idle (load when idle)
- client:media (responsive loading)
- client:only (skip SSR)
Never: client:load (unless justified in ADR)
Linting_Formatting:
primary: Biome (replaces ESLint + Prettier)
config: biome.json
benefits:
- 20x faster than ESLint
- Single tool for lint + format
- Built-in import sorting
- TypeScript-first
Type_Checking:
- TypeScript strict mode
- @astrojs/check for templates
- Type generation from Content Collections
Git_Hooks:
tool: Husky + lint-staged
pre-commit:
- Format/lint staged code files with Biome (biome check --write)
- Fix staged Markdown with markdownlint-cli2
commit-msg:
- Conventional commits enforced via commitlint
pre-push:
- Unit test suite (pnpm run test:unit)
# Type checking (astro check) runs in quality:ci, not in git hooks
TypeMVPShowcaseTool
Unit✅ Mandatory (TDD, ADR-037; runs in quality:ci)✅ MandatoryVitest
MutationOptionalStryker (test:mutate)
E2EManualPlaywright
A11yDev toolsaxe-core + Playwright
PerformanceLighthouseLighthouse CI
Component_Docs:
approach: TypeScript interfaces + JSDoc on component props
features:
- Props documented at the type level
- Playwright e2e specs covering key pages (no visual-regression snapshots)
- "@a11y-tagged accessibility checks in the e2e suite (pnpm run test:a11y)"
API_Docs:
- TypeScript JSDoc
- Generated from types
- Markdown for guides
Primary: GitHub Pages
notes:
- The starter ships a ready-to-use workflow (.github/workflows/deploy.yml)
- Base path derived automatically from package.json name
- Free for public repos
Alternatives:
- Cloudflare Pages (global CDN, Web Analytics included)
- Vercel (great DX)
- Netlify (mature platform)
Build_Time:
- Image optimization via Sharp
- CSS purging via Tailwind
- Bundle analysis via Vite
- Compression (Brotli/Gzip)
Runtime:
MVP:
- Cloudflare Web Analytics
- Uptime monitoring
- Basic error logging
Showcase:
- Real User Monitoring (RUM)
- Core Web Vitals tracking
- Error tracking with source maps
- Session replay (privacy-safe)

The starter’s package.json and versions.json are the single source of truth for exact versions — a hardcoded list here would drift. The headline pins: Astro 7.2.2, Tailwind CSS 4.3.3 (via @tailwindcss/vite), Preact 10.29.8, TypeScript 5.9.3, Biome 2.5.8, Vitest 4.1.10, Playwright 1.62.1, plus @astrojs/mdx, @astrojs/sitemap, @astrojs/preact, and Sharp.

Dev tooling includes Husky, lint-staged, Stryker (@stryker-mutator/core 9.6 for mutation testing), Lighthouse CI, and tsx. Semgrep (SAST) and gitleaks (secret scanning) run in CI via their official containers rather than as devDependencies. Engines require Node >=24.15.0 and pnpm >=10.

{
"scripts": {
"dev": "astro dev",
"build": "pnpm run env:validate && pnpm run tokens:build && astro build",
"preview": "astro preview",
"check": "SITE_URL=${SITE_URL:-http://localhost:4321} astro check",
"format": "biome format . --write",
"lint": "biome check .",
"quality:ci": "pnpm run format:check && pnpm run lint && pnpm run lint:md && pnpm run check && pnpm run test:unit && pnpm run agents:check && pnpm run version:check && pnpm run og:check && pnpm run docs:count",
"tokens:build": "tsx scripts/src/build-tokens.ts",
"design:validate": "tsx scripts/src/validate-contrast.ts",
"perf:baseline": "tsx scripts/src/baseline-performance.ts",
"prepare": "husky"
}
}

See the starter’s package.json for the full script catalogue (testing, performance gates, maintainer tooling).

  1. Astro 7.2.2: Best-in-class static site generator with minimal JavaScript
  2. Tailwind v4: Modern utility CSS with the Oxide engine and CSS-first configuration
  3. Biome: Massive speed improvement over ESLint/Prettier
  4. Preact: Smaller than React for islands that need state
  5. GitHub Pages: Zero-config deploys via the bundled deploy.yml workflow
  • ❌ Multiple build tools (webpack, rollup, etc.)
  • ❌ Heavy component frameworks for simple sites
  • ❌ Overlapping linters and formatters
  • ❌ Client-side routing libraries
  • ❌ Large JavaScript frameworks for minimal interactivity
  • ❌ External image CDNs (use Astro’s built-in optimization)

When updating from older versions:

  1. Astro 5 → 6: Legacy content collections are gone — use the Content Layer (src/content.config.ts, glob() loaders, entries keyed by .id)
  2. Tailwind 3 → 4: Config moves into CSS (@import "tailwindcss" + @theme); the @astrojs/tailwind integration is replaced by @tailwindcss/vite
  3. ESLint → Biome: Run migration command: pnpm dlx @biomejs/biome migrate
  4. React → Preact: Update imports in island components