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 in the official Astro Discord, where the support channels are friendly to beginners.

Keep reading

  1. How to Deploy an Astro Site to Cloudflare Workers

    Put your Astro site online with Cloudflare Workers in four steps. This is how AstroBeginner itself is hosted, so every step has been run for real.

    Tutorials, 7 minute read, November 6, 2026

  2. How to Add Tailwind CSS to Astro

    Add Tailwind CSS to an Astro site with one command, then style your first element. Tested on Astro 7.4 and Tailwind 4.

    Tutorials, 5 minute read, November 6, 2026

  3. How to Add Images to an Astro Site

    Add an image to your Astro site, and let Astro shrink and convert it automatically. One test image went from 62 kB to 5 kB.

    Tutorials, 6 minute read, November 6, 2026

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