Astro Framework for Static Sites
Astro has taken the static‑site world by storm, offering a fresh take on how we build fast, content‑driven websites. Instead of bundling every JavaScript library into the final HTML, Astro lets you ship only what the user actually needs, keeping the payload ultra‑light. In this article we’ll walk through the core ideas behind Astro, spin up a simple site, and explore a couple of real‑world patterns that showcase its power.
What Makes Astro Different?
At its heart, Astro is a compiler that transforms your components into static HTML at build time. Unlike traditional frameworks that hydrate the entire page on the client, Astro lets you decide on a per‑component basis whether to add interactivity. This “islands architecture” means the initial page load is essentially just HTML, CSS, and the minimal JavaScript required for dynamic parts.
Astro also embraces a “bring‑your‑own‑framework” philosophy. You can write components in React, Vue, Svelte, Solid, or even plain HTML—Astro will render them to static markup and only include the runtime for those you explicitly opt‑in. This flexibility reduces lock‑in and lets teams reuse existing component libraries.
Zero‑JS By Default
When you create an Astro component without any client‑side directives, the output is pure HTML. No <script> tags, no runtime overhead. If you need interactivity, you add a directive like client:load or client:idle, and Astro injects the appropriate JavaScript bundle only for that component.
Pro tip: Start every new page with static markup only. Add JavaScript later, only when you’ve measured a real need. This habit keeps your site lean from day one.
Getting Started: A Minimal Astro Project
First, install the Astro CLI and scaffold a new project. The following commands assume you have Node.js ≥ 18 installed.
npm create astro@latest my-static-site
cd my-static-site
npm install
npm run dev
The npm create astro@latest wizard asks a few questions—choose “Minimal” for the starter template. Once the dev server is up, navigate to http://localhost:4321 and you’ll see a bare‑bones homepage rendered as plain HTML.
Folder Structure Overview
- /src/pages – Each
.astrofile becomes a route. - /src/components – Reusable UI pieces, written in any supported framework.
- /public – Static assets like images, favicons, and robots.txt.
- astro.config.mjs – Global configuration, integrations, and build options.
Let’s replace the default homepage with a custom component that showcases Astro’s static rendering.
Example 1: A Simple Blog List
Create src/pages/index.astro with the following content. This component reads a hard‑coded array of posts and renders them as a list. No JavaScript is emitted because we never request client‑side hydration.
<!-- src/pages/index.astro -->
---
const posts = [
{ title: "Getting Started with Astro", slug: "intro-astro", date: "2024-08-01" },
{ title: "Why Islands Architecture Matters", slug: "islands-arch", date: "2024-09-15" },
{ title: "Deploying Astro to Netlify", slug: "netlify-deploy", date: "2024-10-03" },
];
---
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My Astro Blog</title>
<link rel="stylesheet" href="/styles.css" />
</head>
<body>
<h1>Welcome to My Astro Blog</h1>
<ul>
{posts.map(post => (
<li key={post.slug}>
<a href={`/blog/${post.slug}`}>{post.title}</a>
<small> – {post.date}</small>
</li>
))}
</ul>
</body>
</html>
Notice the use of plain JavaScript inside the front‑matter. Astro’s compiler evaluates this at build time, turning the posts.map loop into static <li> elements. The resulting HTML is identical to hand‑written markup, but you retain the flexibility of a data‑driven source.
Adding Interactivity: The Islands Model
Static sites are great for SEO and performance, but many modern experiences require a dash of interactivity—think comment widgets, search boxes, or animated counters. Astro’s island model lets you isolate those dynamic parts without sacrificing the static core.
Example 2: A Counter Component with React
First, install the React integration.
npm i @astrojs/react
# Then add it to astro.config.mjs
import react from "@astrojs/react";
export default defineConfig({
integrations: [react()],
});
Create a React counter in src/components/Counter.jsx and use the client:idle directive so the script loads only after the page becomes idle.
// src/components/Counter.jsx
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div className="counter">
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
Now embed this component on a page.
<!-- src/pages/about.astro -->
---
import Counter from "../components/Counter.jsx";
---
<html lang="en">
<head>
<title>About – Astro Site</title>
</head>
<body>
<h1>About This Site</h1>
<p>This page demonstrates an interactive island using React.</p>
<Counter client:idle />
</body>
</html>
When the browser finishes loading the static markup, it will lazily hydrate the <Counter> component during an idle period. The rest of the page remains static, preserving the performance benefits of a pure HTML site.
Pro tip: Useclient:loadonly for critical UI elements. For non‑essential widgets,client:idleorclient:visibledramatically reduces the initial JavaScript payload.
Content‑Driven Sites with Markdown
One of Astro’s flagship features is its built‑in Markdown support. By treating .md files as first‑class routes, you can power a blog, documentation site, or knowledge base without a separate CMS.
Example 3: Blog Posts as Markdown Files
Place a file called src/content/posts/2024-11-01-astro-tips.md with front‑matter metadata.
---
title: "10 Astro Tips You Should Know"
date: "2024-11-01"
description: "A quick roundup of performance tricks for Astro developers."
tags: ["astro", "performance", "tips"]
---
# Introduction
Astro is already fast, but these tweaks push it even further...
* Use `client:only` for heavy libraries.
* Leverage the `astro:html` pragma to inline critical CSS.
* ...
Astro automatically creates a route at /posts/2024-11-01-astro-tips. To list all posts, you can read the content directory during the build using the import.meta.glob utility.
<!-- src/pages/blog.astro -->
---
const allPosts = import.meta.glob("../content/posts/*.md", { eager: true });
const posts = Object.values(allPosts).map(mod => ({
...mod.metadata,
slug: mod.file.split("/").pop().replace(".md", ""),
}));
---
<html lang="en">
<head>
<title>Blog – Astro Site</title>
</head>
<body>
<h1>Blog</h1>
<ul>
{posts.sort((a, b) => new Date(b.date) - new Date(a.date)).map(post => (
<li key={post.slug}>
<a href={`/blog/${post.slug}`}>{post.title}</a>
<small> – {post.date}</small>
</li>
))}
</ul>
</body>
</html>
The import.meta.glob call runs at build time, turning each Markdown file into a module that exports its front‑matter and compiled HTML. This pattern enables a fully static blog with zero runtime data fetching.
Real‑World Use Cases
Marketing landing pages benefit from Astro’s lightning‑fast load times. A typical product launch page can be built with a handful of static sections, a small form component that hydrates on submit, and SEO‑optimized meta tags—all without a single bundle larger than 10 KB.
Documentation portals often consist of thousands of Markdown pages. Astro’s built‑in MDX support lets you embed interactive React or Vue demos directly within documentation, giving developers a live playground without sacrificing static performance.
E‑commerce storefronts can use Astro for the catalog and product detail pages, while delegating cart and checkout flows to a client‑side framework. By rendering product listings as static HTML, you reduce server load and improve Core Web Vitals, while still offering a dynamic shopping cart via an isolated island.
Note: For large e‑commerce sites, consider using Astro’s prerender mode in combination with a headless CMS. This approach pre‑generates popular pages while falling back to server‑side rendering for rarely visited items.
Performance Benchmarks
Astro’s default output often scores above 95 on Google PageSpeed Insights for both mobile and desktop. The key contributors are:
- Zero‑JS first paint – The browser can render meaningful content instantly.
- Selective hydration – Only the islands you flag receive JavaScript.
- Built‑in image optimization – The
Imagecomponent automatically serves WebP/AVIF and sizes images to the viewport.
In a recent case study, a marketing site built with Astro loaded in 0.42 seconds on a 3G connection, compared to 1.9 seconds for a comparable React‑only implementation. The reduction in JavaScript payload (from 250 KB to 12 KB) was the primary driver.
Deploying Astro Sites
Because Astro outputs static HTML, CSS, and optional JavaScript bundles, you can host the dist/ folder on any static‑file CDN. Popular choices include Netlify, Vercel, Cloudflare Pages, and AWS S3 + CloudFront.
For Netlify, simply add a netlify.toml file:
[build]
publish = "dist"
command = "npm run build"
Vercel requires no configuration beyond a vercel.json if you use the default build script. Both platforms automatically detect the output folder and serve it with edge caching, ensuring sub‑second response times worldwide.
Advanced Tips & Tricks
- SSR for dynamic data – While Astro shines as a static generator, you can enable server‑side rendering for specific routes using the
output: "server"option inastro.config.mjs. - Component islands in MDX – Embed interactive demos directly in documentation by writing MDX files that import React or Svelte components.
- Asset pipelines – Use the
@astrojs/imageintegration to automatically generate responsive<picture>elements, reducing image‑load time. - Environment variables – Prefix variables with
PUBLIC_to expose them to client‑side code, keeping secrets server‑only.
Pro tip: When you need a global layout (header, footer, SEO tags), create a src/layouts/BaseLayout.astro file and wrap each page with it. This DRY approach ensures consistent markup and simplifies future redesigns.
Conclusion
Astro redefines how we think about static sites by marrying the simplicity of pure HTML with the power of modern component frameworks. Its island architecture, zero‑JS‑by‑default philosophy, and seamless Markdown integration make it a go‑to choice for marketers, developers, and documentation teams alike. By starting with static markup and adding interactivity only where it truly adds value, you’ll deliver faster, more SEO‑friendly experiences without the baggage of large JavaScript bundles. Whether you’re building a personal blog, a corporate landing page, or a hybrid e‑commerce storefront, Astro gives you the flexibility to scale performance and complexity on your own terms.