Skip to content
← All posts
Web Development8 min read

Edge-Native Micro-SaaS with Astro 6 and Preact

A deep dive into building ultra-fast, edge-native micro-SaaS applications using Astro 6, Preact, and Cloudflare Workers. Zero-BS engineering for solo devs.

bj

by jtt

Solo Developer & Writer

Edge-Native Micro-SaaS with Astro 6 and Preact
In this post

TL;DR: Ship velocity dictates micro-SaaS survival. By leveraging Astro 6’s zero-JS defaults, hydrating minimal Preact islands only when necessary, and shifting state synchronization to Nanostores over edge-native infrastructure, solo developers can achieve 100/100 Lighthouse scores without sacrificing developer experience.

The modern web is bloated. We’re shipping megabytes of JavaScript to render static text, blocking the main thread, and paying the architectural tax of complex state management systems when simple tools suffice.

For indie hackers and solo founders building micro-SaaS, this complexity is more than a performance issue—it’s a massive drag on ship velocity. When your runway is measured in weekends rather than venture capital rounds, every abstraction must earn its keep.

In this deep dive, we’ll architect a highly resilient, edge-native micro-SaaS using Astro 6, Preact, and Nanostores, adopting a brutalist approach to web architecture. Zero fluff. Pure outcome.

The Brutalist Stack Philosophy

Brutalist web architecture isn’t about looking ugly; it’s about exposing the structural honesty of the system. It means stripping away the glassmorphism, the unnecessary DOM layers, and the heavy runtime frameworks.

Our core tenets:

  1. Zero-JS by Default: Ship HTML. Hydrate only what needs interaction.
  2. Edge-Native Deployment: Push everything to the edge (Vercel, Cloudflare) for minimal latency.
  3. Decoupled State: Use atomic, framework-agnostic state stores instead of massive context providers.

Why Astro 6?

Astro’s island architecture is the perfect fit for micro-SaaS. You get the SEO and performance benefits of a static site generator, but you can seamlessly drop in interactive components (React, Preact, Vue) exactly where they’re needed.

Astro 6 takes this further with enhanced View Transitions and better content collections, allowing for app-like SPA navigation without the SPA overhead.

Architecting the Edge-Native Payload

Let’s look at the architectural flow of our micro-SaaS.

graph TD
    A[Client Request] --> B[Edge CDN / Vercel]
    B --> C{Astro 6 Router}
    C -->|Static Routes| D[Pre-rendered HTML]
    C -->|Dynamic Routes| E[Serverless Edge Function]
    E --> F[Turso SQLite Edge DB]
    D --> G[Client Browser]
    E --> G
    G --> H[Nanostores State]
    H --> I[Preact Islands Hydration]

1. Minimalist State with Nanostores

When you ditch the monolithic SPA, you lose the massive AppContext that usually wraps your entire application. This is a feature, not a bug.

Instead of binding state tightly to our UI framework, we use Nanostores. It’s framework-agnostic, meaning our Astro components, Preact islands, and vanilla JS utilities can all subscribe to the same atomic state atoms.

// src/store/auth.ts
import { atom } from 'nanostores';

export type UserSession = {
  id: string;
  role: 'free' | 'pro';
} | null;

// Atomic, zero-dependency state
export const $session = atom<UserSession>(null);

2. Hydrating Preact Islands

React 19 is great, but Preact gives us 95% of the API surface for a fraction of the bundle size. In a micro-SaaS dashboard, this swap alone can shave 30-40kb off your initial load.

We only hydrate components that require immediate interactivity.

---
// src/pages/dashboard.astro
import MainLayout from '../layouts/MainLayout.astro';
import { UserProfile } from '../components/preact/UserProfile';
import { DataGrid } from '../components/preact/DataGrid';
import { $session } from '../store/auth';

// Server-side validation
const session = Astro.locals.session;
if (!session) return Astro.redirect('/login');
---

<MainLayout title="Dashboard">
  <!-- Static HTML, zero JS -->
  <header>
    <h1>Welcome back, {session.name}</h1>
  </header>

  <!-- Hydrate immediately: Critical path -->
  <UserProfile client:load initialSession={session} />

  <!-- Hydrate only when scrolled into view -->
  <DataGrid client:visible data-source="/api/metrics" />
</MainLayout>

3. Edge-Native Data Access

Instead of standing up a heavy Node.js monolith, we execute database queries directly from the edge. By pairing Astro’s SSR adapters with a distributed database like Turso (SQLite on the edge), we guarantee sub-50ms data fetching globally.

// src/pages/api/metrics.ts
import type { APIRoute } from 'astro';
import { db } from '../../lib/db'; // Turso Edge DB client

export const GET: APIRoute = async ({ request, locals }) => {
  const session = locals.session;

  if (!session || session.role !== 'pro') {
    return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });
  }

  // Executes at the edge node closest to the user
  const metrics = await db.execute('SELECT * FROM user_metrics WHERE user_id = ?', [session.id]);

  return new Response(JSON.stringify(metrics.rows), {
    headers: { 'Content-Type': 'application/json' }
  });
};

Optimizing for the 100/100 Lighthouse

Achieving perfect Lighthouse scores isn’t a vanity metric—it’s a proxy for user experience and organic SEO visibility.

To ensure we hit 100 across the board:

  1. Font Loading: Use font-display: swap and self-host fonts (like Inter or Geist) to prevent layout shifts.
  2. Image Optimization: Let Astro handle image optimization natively. Always provide width and height attributes to prevent Cumulative Layout Shift (CLS).
  3. Avoid Main Thread Blocking: Defer third-party scripts (analytics, support widgets) using client:idle or standard defer attributes.
---
import { Image } from 'astro:assets';
import dashboardPreview from '../assets/dashboard.png';
---

<!-- Astro automatically optimizes to WebP/AVIF and injects dimensions -->
<Image
  src={dashboardPreview}
  alt="Micro-SaaS Dashboard Preview"
  width={800}
  height={600}
  loading="lazy"
  decoding="async"
/>

The Generative SEO Advantage

Writing content for AI search engines (like ChatGPT or Google’s SGE) requires a different structure than traditional SEO. This is called Generative Engine Optimization (GEO).

By structuring our markup with highly semantic HTML, clear data tables, and explicit H2/H3 hierarchies, we ensure that LLMs can easily parse and synthesize our content as authoritative answers.

Conclusion

Architecting a micro-SaaS doesn’t require a bloated enterprise stack. By combining Astro 6, Preact, and Nanostores, you can achieve edge-native performance, zero-FOUC rendering, and massive improvements to your shipping velocity.

Keep it simple. Keep it fast. Ship it.

Deep Dive: Preact Islands vs Vanilla JS

When architecting a micro-SaaS, a common debate arises: should you use a lightweight framework like Preact, or stick entirely to Vanilla JavaScript and Web Components?

Vanilla JS is unmatched for raw performance and minimal payload. For simple toggles, theme switchers, or basic form validation, Vanilla JS should be your default. However, when dealing with complex, reactive state—such as a data grid with sorting, filtering, and real-time updates—Vanilla JS can quickly devolve into a fragile, imperative mess of DOM manipulation and event listeners.

This is where Preact islands shine. By confining the framework to specific, bounded areas of the page (islands), you get the declarative, component-driven developer experience of React without paying the cost of a monolithic Single Page Application.

Strategy: Progressive Enhancement

A robust approach involves progressive enhancement:

  1. Baseline HTML: Ensure the core functionality (e.g., submitting a form) works without JavaScript. This provides resilience and baseline accessibility.
  2. Vanilla Interactivity: Add lightweight Vanilla JS for simple, non-reactive interactions (e.g., expanding an accordion).
  3. Preact Islands for Complexity: Drop in a Preact island for the highly interactive, state-heavy components (e.g., the complex pricing calculator or real-time dashboard).

By strategically combining these approaches, you optimize for both ship velocity and end-user performance, ensuring your micro-SaaS remains maintainable as it scales.

Data Fetching: Edge vs Static Generation

Another critical architectural decision is how you fetch and render data. Astro provides several rendering modes, and choosing the right one is essential for a high-performance micro-SaaS.

  • Static Site Generation (SSG): This is the default. Pages are rendered at build time. Ideal for marketing pages, documentation, and the blog (like this very post). It offers maximum performance and cacheability.
  • Server-Side Rendering (SSR) at the Edge: Pages are rendered on demand at the edge node closest to the user. This is necessary for authenticated routes (like the user dashboard) where data changes frequently and is unique to each user.

By leveraging edge-native infrastructure (like Vercel or Cloudflare Workers) for SSR, you minimize the “time to first byte” (TTFB) compared to a traditional Node.js server located in a single region.

Hybrid Rendering

The real power of Astro lies in hybrid rendering. You can statically generate your marketing pages for global performance, while selectively opting into SSR for specific, authenticated routes. This best-of-both-worlds approach is a game-changer for indie hackers aiming for enterprise-grade architecture on a solo budget.

Topics

Get updates when I ship

Join the newsletter for build logs, tutorials, and product launches. No spam, unsubscribe anytime.

Subscribe
Share

Written by Jordan Thirkle

Stay-at-home dad shipping AI-accelerated products. Posts come from real builds, not theory.

0