Free Astro tutorials for complete beginners.

Beginner's Guide to Astro

How to Add a Blog to Your Astro Site

Add a blog to your Astro site with content collections. Write posts in Markdown and let Astro build the pages for you.

Tested on Astro 7.4

Cover image for How to Add a Blog to Your Astro Site
In this guide
  1. Step 1: Write a post
  2. Step 2: Define the collection
  3. Step 3: Create the blog index
  4. Step 4: Create a page for each post
  5. Step 5: Check it works
  6. Frequently asked questions

An Astro blog is a folder of Markdown files. Each file becomes a post, and you don’t need a database. This tutorial assumes you already have a project with a layout. If you don’t, start with how to make a website with Astro.

Step 1: Write a post

Create src/content/posts/hello-world.md:

---
title: Hello, world
date: 2026-11-06
---

This is my **first** blog post, written in Markdown.

Step 2: Define the collection

Create src/content.config.ts, directly inside src:

import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';

const posts = defineCollection({
  loader: glob({ base: './src/content/posts', pattern: '**/*.md' }),
  schema: z.object({
    title: z.string(),
    date: z.coerce.date(),
  }),
});

export const collections = { posts };

The loader tells Astro where your posts are. The schema lists what each post needs.

Step 3: Create the blog index

Create src/pages/blog/index.astro:

---
import { getCollection } from 'astro:content';
import Layout from '../../layouts/Layout.astro';

const posts = (await getCollection('posts')).sort(
  (a, b) => b.data.date.valueOf() - a.data.date.valueOf(),
);
---
<Layout title="Blog">
  <h1>Blog</h1>
  <ul>
    {posts.map((post) => (
      <li><a href={`/blog/${post.id}/`}>{post.data.title}</a></li>
    ))}
  </ul>
</Layout>

The sort matters here, because Astro doesn’t return posts in any particular order.

Step 4: Create a page for each post

Create src/pages/blog/[id].astro, with the square brackets in the name:

---
import { getCollection, render } from 'astro:content';
import Layout from '../../layouts/Layout.astro';

export async function getStaticPaths() {
  const posts = await getCollection('posts');
  return posts.map((post) => ({
    params: { id: post.id },
    props: { post },
  }));
}

const { post } = Astro.props;
const { Content } = await render(post);
---
<Layout title={post.data.title}>
  <h1>{post.data.title}</h1>
  <p>{post.data.date.toDateString()}</p>
  <Content />
</Layout>

Step 5: Check it works

Restart your dev server and visit /blog/. You should see your post in the list. Click it to read it.

To publish another post, add another .md file to the same folder.

Frequently asked questions

Is there a faster way to start a blog?

Yes. Create a new project with the official blog template, which already includes posts, an RSS feed and a sitemap. Run npm create astro@latest with the template option set to blog.

Can I use images in my posts?

Yes. Put images in a folder near your post and link to them with normal Markdown image syntax.

Stuck on a step?

Check the common errors guide, look up a word in the glossary, or ask the friendly people in the official Astro and EmDash Discords. How to ask so people can help.

Keep reading

  1. How to Register a Domain Name and Connect It to Your Astro Site

    Buy a domain for about $11 a year, then point it at Cloudflare or Netlify. We did this for astronursery.com, and these are the exact steps.

    Tutorials, 8 minute read, November 8, 2026

  2. How to Add Google Analytics to an Astro Site (and a Simpler Option)

    Paste Google's tag into your Astro layout with one small change, is:inline, and it works on every page. Or use Cloudflare Web Analytics, which needs no cookie banner.

    Tutorials, 6 minute read, November 8, 2026

  3. How to Add a Contact Form to an Astro Site (No Server Needed)

    A static site can't receive form submissions on its own. A free form service can. Here's a working contact form in ten lines, with spam protection built in.

    Tutorials, 7 minute read, November 8, 2026

Try "blog", "deploy" or "EmDash".