---
title: "EmDash + Astro: Why the CMS Is Built on Astro"
description: "Why EmDash chose Astro as its foundation. Zero JS by default, component islands, server-rendered pages, and what it means for your site."
article_type: child
canonical: https://dashstro.com/learn/emdash-astro
---
I built dashstro.com on EmDash, and the first question people ask isn't about the CMS — it's about Astro. Why Astro? Not Next.js, not Nuxt, not SvelteKit. The answer is architectural, and it goes to the heart of what makes EmDash different from every other CMS in this space.

EmDash didn't adapt itself to Astro. It was designed specifically for Astro's model. That distinction matters a lot in practice.

## What Astro actually is

Astro is a web framework that renders pages on the server and ships zero JavaScript to the browser by default. That last part is the key: zero JS by default. Not "minimal JS" or "lightweight JS" — zero. If you want JavaScript on the client, you opt in. You add it where you actually need it.

This is the opposite of Next.js and Nuxt, which ship a JavaScript runtime to every page and hydrate components on the client even when those components don't need interactivity. For a content site — articles, docs, a blog — most of your pages are static. There's nothing to hydrate. Sending a React runtime to render a blog post is waste by design.

## Component islands: interactive where you need it

When you do need interactivity — a search box, a comment form, the EmDash admin panel — Astro handles it with component islands. An island is an isolated interactive component rendered on the client. The rest of the page is static HTML.

EmDash uses this directly. The admin panel at /_emdash/admin is a React application — a full island of interactivity. Your public site is Astro — server-rendered HTML with no framework overhead. The same Astro project handles both, and neither interferes with the other.

You can also use any frontend framework for your own islands. React, Svelte, Vue, Preact, SolidJS — Astro supports them all. Pick what you know. It won't affect the rest of the page.

## Server rendering for CMS content

EmDash is entirely server-rendered — no static paths, no build-time generation. When a reader requests /learn/emdash-astro, Astro fetches the entry from D1, renders the Portable Text to HTML, and returns the page. This matters because CMS content is dynamic. You can publish an article and it's live immediately. No rebuild required.

Astro's .astro file format makes server rendering clean to write. You do data fetching at the top in a frontmatter block — just TypeScript — and template rendering below. There's no useEffect, no loading state management, no client-side data fetching. The data arrives before the HTML ships.

## The .astro template system

Astro components use a file format that's familiar if you've written PHP or classic server-side templates — frontmatter for logic, HTML-like markup below. But it's TypeScript, type-safe, and has full IDE support. You import EmDash's content APIs at the top, fetch your data, and render it below with JSX-like syntax.

EmDash provides Astro UI components — EmDashHead for SEO meta, PortableText for rendering rich content, Image for media, WidgetArea for dynamic sidebar widgets. They're native Astro components. No adapter layer, no abstraction mismatch.

## Astro vs Next.js vs Nuxt for a CMS

Here's how the frameworks compare on the dimensions that matter for a content site:

| Default JS shipped | Zero | React runtime always | Vue runtime always |
| --- | --- | --- | --- |
| Component model | Islands (any framework) | React only | Vue only |
| Rendering model | SSR, SSG, hybrid | SSR, SSG, RSC | SSR, SSG, hybrid |
| Cloudflare Workers support | Official adapter | Partial, edge runtime flag | Partial, Nitro adapter |
| Content-first design | Yes — built for content sites | App-first, content secondary | App-first, content secondary |

:::pullquote
Zero JavaScript by default isn't a constraint — it's the correct starting point for a content site. You add JS where you need it, not everywhere by default.
:::

## What this means for performance

An EmDash page on Cloudflare Workers is fast in a way that's hard to achieve with React-based frameworks. There's no hydration delay. There's no JavaScript bundle to parse. The browser receives complete HTML, renders it, and you're reading. Time to interactive is the same as time to first paint.

Cached responses from Cloudflare's edge hit in 10-30ms. Even uncached server-rendered pages with database queries come in at 50-150ms. This is what you get when your framework doesn't fight against you on performance.

## Developer experience in practice

Building on EmDash + Astro feels different from building a CMS-backed Next.js site. There are no client-side data fetching hooks to manage. You don't think about API route handlers for page data. You don't worry about hydration mismatches. The data is there when the template runs — that's it.

TypeScript types are generated from your schema via npx emdash types. Your editor knows what fields exist on every collection. The content API returns typed objects. You catch mismatches at edit time, not in production.

The Astro choice isn't incidental to EmDash — it's the architecture. A CMS built for the edge, where content is the product and JavaScript is a guest, not the host. If that sounds like the right model to you, start with the build guide below.

[Build your first EmDash site →](/learn/build-first-emdash-website)

