Astro is a modern web framework designed with one core philosophy: ship less JavaScript. While most frontend frameworks run entirely in the browser, Astro renders HTML on the server and sends zero JavaScript to the client by default. The result? Websites that load in milliseconds.
In this guide, we’ll walk through everything you need to know to get started with Astro — from installation to deploying your first site.
Why Astro?
Before we dive into the how, let’s talk about the why. Modern web development has a JavaScript problem. Rich Single Page Applications (SPAs) ship hundreds of kilobytes of JavaScript before users see any content. This directly harms:
- Performance – Users on slow connections wait longer
- SEO – Search engines struggle to index JavaScript-heavy pages
- Accessibility – Screen readers and assistive tech work better with plain HTML
- Battery life – Parsing JS is CPU-intensive on mobile devices
Astro solves this by treating JavaScript as an optional enhancement rather than the default.
Prerequisites
Before starting, make sure you have:
- Node.js v18.17.1 or later (or Bun/Deno)
- A code editor (VS Code with the official Astro extension is recommended)
- Basic knowledge of HTML and CSS
Installation
Creating a new Astro project is straightforward:
# With npm
npm create astro@latest my-blog
# With Bun
bun create astro@latest my-blog
# With pnpm
pnpm create astro@latest my-blog
The CLI wizard will walk you through the options. For a blog, choose the Blog starter template when prompted.
astro Launch sequence initiated.
dir Where should we create your new project?
./my-blog
tmpl How would you like to start your new project?
● Use blog template
Project Structure
Once created, your project will look like this:
my-blog/
├── public/ # Static files (images, fonts, favicon)
├── src/
│ ├── components/ # Reusable Astro/React/Vue/Svelte components
│ ├── content/ # Markdown/MDX blog posts
│ │ ├── config.ts # Content collection schema
│ │ └── blog/ # Your .md / .mdx files
│ ├── layouts/ # Page layouts
│ ├── pages/ # File-based routing
│ └── styles/ # Global CSS
├── astro.config.mjs # Astro configuration
└── package.json
Content Collections
One of Astro’s most powerful features for blogs is Content Collections — a type-safe way to manage your Markdown files.
Define your schema in src/content/config.ts:
import { defineCollection, z } from "astro:content";
const blog = defineCollection({
type: "content",
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
tags: z.array(z.string()).default([]),
featured: z.boolean().default(false),
}),
});
export const collections = { blog };
Now create a post in src/content/blog/my-first-post.md:
---
title: "My First Post"
description: "Welcome to my blog!"
pubDate: "2024-12-01"
tags: ["intro", "blog"]
---
Hello, world! This is my first Astro blog post.
Querying and Rendering Posts
Astro makes it simple to query your content collections:
---
// src/pages/index.astro
import { getCollection } from 'astro:content';
// Get all non-draft posts, sorted by date
const posts = (await getCollection('blog', ({ data }) => !data.draft))
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
---
<ul>
{posts.map((post) => (
<li>
<a href={`/blog/${post.slug}`}>{post.data.title}</a>
<time>{post.data.pubDate.toLocaleDateString()}</time>
</li>
))}
</ul>
To render a single post, use the render function:
---
// src/pages/blog/[...slug].astro
import { getCollection, render } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { slug: post.slug },
props: { post },
}));
}
const { post } = Astro.props;
const { Content, headings } = await render(post);
---
<article>
<h1>{post.data.title}</h1>
<Content />
</article>
Islands Architecture
Astro’s killer feature is the Islands Architecture. You can use any component framework (React, Vue, Svelte, Solid) for interactive parts, while keeping the rest as static HTML.
---
import SearchBar from '../components/SearchBar.jsx';
import CommentSection from '../components/CommentSection.vue';
---
<!-- This nav is static HTML - no JS shipped -->
<nav>...</nav>
<!-- This search bar loads React only when visible -->
<SearchBar client:visible />
<!-- Comments load after the page becomes interactive -->
<CommentSection client:idle />
Client Directives
| Directive | When JS loads |
|---|---|
client:load | Immediately on page load |
client:idle | When browser is idle |
client:visible | When component enters viewport |
client:media | When media query matches |
client:only | Never SSR, always client |
Syntax Highlighting
Astro ships with Shiki for code syntax highlighting — no plugins needed. It supports dual themes for dark and light mode:
// astro.config.mjs
export default defineConfig({
markdown: {
shikiConfig: {
themes: {
light: "github-light",
dark: "github-dark",
},
wrap: true,
},
},
});
Building and Deploying
Build
npm run build
# Output goes to ./dist/
Deploy to Vercel
npm install @astrojs/vercel
// astro.config.mjs
import vercel from "@astrojs/vercel";
export default defineConfig({
output: "server", // or 'hybrid'
adapter: vercel(),
});
Deploy to GitHub Pages
// astro.config.mjs
export default defineConfig({
site: "https://yourusername.github.io",
base: "/your-repo",
});
Performance Results
Let’s see what Astro gives us by default. Running Lighthouse on a basic blog:
| Metric | Before (React SPA) | After (Astro) |
|---|---|---|
| Performance | 68 | 99 |
| First Contentful Paint | 2.4s | 0.3s |
| Largest Contentful Paint | 4.1s | 0.6s |
| Total Blocking Time | 540ms | 0ms |
| JavaScript shipped | 287 KB | 0 KB |
The numbers speak for themselves.
Integrations Ecosystem
Astro has a rich ecosystem of official and community integrations:
# Add React
npx astro add react
# Add Tailwind CSS
npx astro add tailwind
# Add a sitemap
npx astro add sitemap
# Add an RSS feed
npx astro add rss
Each integration is a single command away and configures itself automatically.
Next Steps
Now that you understand the basics, here’s where to go next:
- Astro Docs — The official documentation is excellent
- Astro Themes — Browse community themes for inspiration
- Add MDX — Use JSX components inside Markdown with
@astrojs/mdx - Add Search — Integrate Pagefind for zero-config static search
- Add a CMS — Connect to Contentful, Sanity, or any headless CMS
Conclusion
Astro represents a fundamental rethinking of how we build content-focused websites. By defaulting to zero JavaScript and only hydrating what needs to be interactive, it achieves performance that other frameworks simply can’t match.
Whether you’re building a personal blog, a documentation site, or a marketing page, Astro gives you the tools to build something fast, maintainable, and enjoyable to work on.
Give it a try — your users (and your Lighthouse scores) will thank you.