Stack Innovations / Services / Web / Astro

Astro, shipping zero JS by default.

Most "modern" sites ship 400 KB of framework before a single byte of content. We build with Astro — static HTML by default, JavaScript only on the islands that need it. Content Collections typed with Zod, view transitions baked in, multi-framework where it makes sense, and Lighthouse 100s as a starting line, not a goal.

01 — In numbers

Five years shipping
sites that just open.

Each stat is a Zod field in our Content Collections schema. Hover any to see the schema definition. Counters scrub with scroll — z.number().min(...) validating every claim.

projectsShipped
0+ Astro sites shipped
projectsShipped: z.number()
  .int()
  .min(38)
  .describe('shipped to prod'),
contentEntries
0+ Content entries modeled
contentEntries: z.number()
  .int()
  .min(2400),
avgLighthouse
0/100 Avg Lighthouse score
avgLighthouse: z.number()
  .min(95)
  .max(100),
jsByDefault
0KB JS shipped by default
jsByDefault: z.literal(0)
  .describe(
    'before any island hydrates'
  ),
02 — What we build

A full-stack Astro practice.

Click the file tree on the left — the active capability opens in the editor pane, rendered as a real .astro file or config. Each pane is a working pattern we've shipped.

Stack · Astro 5.x ~/stack/src/pages/index.astro build · 0 errors A S
.astro src/pages/index.astro SHIPPED

Component islands, hydrated only where needed.

uid: page::index updated: 09:42 today by: stack-eng
summary · what this gets you

Astro renders everything to static HTML at build time. Then for the small parts that need interactivity (a form, a cart, a search box), you opt-in with client:load, client:visible, client:idle, or client:only. The page ships maybe 4 KB of JS instead of 400 KB.

items · what we customize
  • Hydration directives audited per-component
  • client:visible for below-the-fold
  • client:idle for low-priority widgets
  • client:only="react" for client-only libs
  • JS budget per route, enforced in CI
content/config.ts collections.articles · +14 more TYPED

Content Collections, typed all the way down.

uid: collection::articles updated: yesterday by: stack-eng
summary

Every Markdown / MDX file is typed with a Zod schema. getCollection() returns fully-typed entries. We design the collection schemas like database tables — with refinements, refs, defaults — so writers can't ship malformed frontmatter.

items
  • Zod schemas · refinements & refs
  • MDX with custom components
  • Reference fields · reference('authors')
  • Auto-generated routes from [...slug].astro
  • Content Layer API for API-sourced content
astro.config.mjs react · vue · svelte · solid INTEGRATED

Multi-framework, right tool per island.

uid: integrations.frameworks updated: 2d ago by: stack-eng
summary

Astro doesn't pick a winner — React, Vue, Svelte, Solid, Preact, all coexist. We pick the right framework per island: React where the team's skill is, Svelte where bundle size matters, Solid where we need fine-grained reactivity. Every island is its own tree, no shared runtime.

items
  • React, Vue, Svelte, Solid, Preact, Lit
  • One island, one framework, no leak
  • Per-island bundle splitting
  • Shared design tokens via CSS vars
performance · SEO LCP · CLS · INP · TTFB A-GRADE

Performance & SEO, baseline 100, not target.

uid: perf.budget updated: 4d ago by: stack-eng
summary

Astro's static-by-default model + image optimization + prefetch on viewport + critical CSS inlining + zero hydration cost = real Lighthouse 100s on real devices. We layer in JSON-LD, Open Graph, sitemaps, hreflang, and CI perf budgets that fail the build on regressions.

items
  • Image · AVIF + WebP + responsive srcset
  • Prefetch · strategy: 'viewport'
  • JSON-LD per content type
  • Sitemap + hreflang + canonical
  • CI perf budget · fails on regression
view transitions named: hero · +12 SMOOTH

View transitions, page changes that feel native.

uid: transitions.named updated: 1w ago by: stack-eng
summary

Astro's <ViewTransitions /> ships native browser View Transition API support out of the box. We design transition pairs — hero images, titles, sticky headers — so navigations feel like an SPA without ever becoming one.

items
  • transition:name="hero" across routes
  • Per-route fallback animations
  • Persistent islands across nav
  • Reduced-motion respect by default
@astrojs/* vercel · cloudflare · node · netlify DEPLOYED

Adapters & deploys, same code, any runtime.

uid: adapter.runtime updated: 2w ago by: stack-eng
summary

Static, hybrid, or fully server — pick the runtime that fits the page. We ship pages on Cloudflare for global edge, API routes on Vercel functions, marketing pages purely static, all from the same monorepo. Adapter swap is a one-line config change.

items
  • Vercel / Cloudflare / Netlify / Node adapters
  • output: 'hybrid' · per-route mode
  • Server Islands · async server-rendered
  • Astro DB · Turso / libSQL on the edge
03 — Islands → JS budget

Click an island.
The bundle rebuilds.

This is what makes Astro itself: every interactive component is opt-in. Cycle the hydration directive on each island below — the rendered page on the right shows hydration boundaries, and the JS budget at the bottom updates in real time. Anime.js spring on directive change, Mo.js burst on the build button.

components · src/ click to cycle →
stackinnovations.com/launch preview
build output live
0.0 KB JS
budget: 30 KB
    04 — Why us

    Stack Innovations vs the typical Astro build.

    Same framework, two astro.config.mjs files. The diff tells the story.

    typical/astro.config.mjs — default scaffold
    import { defineConfig } from 'astro/config'
    
    export default defineConfig({})
    
    // no integrations
    // no image config
    // no prefetch
    // no view transitions
    // no adapter
    // shipped to prod — everywhere.
    
    stack/astro.config.mjs — Stack Innovations
    import { defineConfig } from 'astro/config'
    import react   from '@astrojs/react'
    import svelte  from '@astrojs/svelte'
    import sitemap from '@astrojs/sitemap'
    import vercel  from '@astrojs/vercel'
    
    export default defineConfig({
      site: 'https://stackinnovations.com',
      integrations: [react(), svelte(), sitemap()],
      prefetch: {
        prefetchAll: true,
        defaultStrategy: 'viewport',
      },
      image: {
        domains: ['cdn.stackinnovations.com'],
        formats: ['avif', 'webp'],
      },
      output: 'hybrid',
      adapter: vercel({ webAnalytics: true }),
      experimental: {
        serverIslands: true,
        contentLayer: true,
      },
      build: { inlineStylesheets: 'auto' },
    })
    
    typical · empty config, defaults everywhere Stack · integrations, image, prefetch, hybrid, adapter, experimental
    05 — Multi-framework playground

    Four frameworks,
    one page.

    Astro doesn't pick a winner. Below: four counter components, each authored in a different framework, each its own island, all on the same page. Click the buttons — each counter has its own state because each island is its own runtime tree. No leaks, no shared store.

    React Counter.tsx client:visible
    0 useState<number>
    2.4 KB JS · React island
    Vue Counter.vue client:visible
    0 ref(0)
    3.1 KB JS · Vue island
    Svelte Counter.svelte client:idle
    0 $state(0)
    0.9 KB JS · Svelte island
    Solid Counter.tsx client:load
    0 createSignal(0)
    1.6 KB JS · Solid island

    Each island has its own state because each is its own framework runtime. Clicking React's button does nothing to Vue's counter — they're isolated by design. To share state, you reach for HTML attributes, URL state, or a tiny shared store. Architectural isolation is the feature, not a bug.

    06 — How it ships

    Six weeks,
    shipped at 100.

    1. w 01

      Audit + content modeling

      Lighthouse baseline of the existing site, content audit, Zod schema design for Content Collections, IA review.

    2. w 02

      Astro scaffold

      Astro 5 scaffolded, TypeScript strict, Tailwind, framework integrations, design tokens, perf budgets in CI.

    3. w 02–04

      Components + islands

      .astro components for the static spine, framework-of-choice islands for interactivity, view transitions across routes, MDX for long-form.

    4. w 04

      Performance + SEO

      Image pipeline (AVIF / WebP / responsive), prefetch tuning, JSON-LD, sitemaps, hreflang. CI fails on perf regression.

    5. w 06

      Migration + launch

      Content migration via Content Layer or migrate-as-you-go. astro build, adapter wired, DNS cutover.

    6. Care plan

      Astro version bumps, framework integration upgrades, perf monitoring, monthly review. Features, not tickets.

    Booking Q3 2026 · Avg engagement: 6 weeks · Reply within 24h