Learning Astro by Making (this) Blog

Learning Astro by Making (this) Blog

A post in a blog about the blog in which the post is in. (wow, very meta)

Kale
June 21, 2025
5 min 50 sec

I had heard of Astro in the past, but I never really got around to learning it. I had also wanted to start a blog to talk about a bunch of different things, like Web Dev and AI. But the most recent spark was Theo’s T3 Chat Cloneathon, a competition to build an open-source clone of T3 Chat. I decided that I wanted to make sort of a devlog of my process building during the competition, and thought a blog would be the best place to do so.

What Is Astro?

Astro is a modern, lightweight web framework designed for building fast, content-focused websites. It’s built with performance and developer experience in mind, making it an excellent choice for everything from personal blogs and marketing sites to e-commerce platforms and documentation.

Astro’s Main Concepts

One of Astro’s most revolutionary features is its “Islands Architecture.” This approach allows you to render your entire website to static HTML by default. Then, for interactive components, you can selectively “hydrate” only those specific islands of JavaScript on the client. This drastically reduces the amount of JavaScript sent to the browser, leading to significantly faster load times.

Astro also boasts zero JavaScript by default. This means that unless you explicitly tell Astro to include JavaScript for a particular component, none will be shipped. This philosophy contributes to the framework’s impressive performance metrics.

Being Built for Performance

Beyond its Islands Architecture and zero-JS default, Astro offers several other performance optimizations:

  • HTML-first: Generates static HTML, which is inherently fast to parse and render.
  • Smart Bundling: Automatically splits your code into smaller chunks, delivering only what’s needed for each page.
  • Asset Optimization: Handles image optimization and other asset transformations out of the box.

Before Building

Before I even began building this blog, I watched a couple of YouTube videos to get a grasp on how Astro works:

Getting Started

I started by creating a new Astro project using the create-astro command, then I created a main layout component that would be used for every page. It contained a navbar, content, and a footer, as well as some basic metadata. Then, I added Tailwindcss for styling the site, and added some styling to the main layout component.

Next, I added a theme toggle to the header:

Dark/Light Theme

I started playing around with a dark/light theme toggle, and eventually I settled upon the implementation below, which is almost the exact same as the tutorial on the Astro Docs.

<!-- ThemeIcon.astro -->

<Button id="theme-toggle">
  <div class="absolute transform translate-x-4 dark:-translate-x-4" />
  <MoonIcon />
  <SunIcon />
</Button>

<script is:inline>
  const theme = (() => {
    const localStorageTheme = localStorage?.getItem("theme") ?? ''
    if (['dark', 'light'].includes(localStorageTheme)) {
      return localStorageTheme
    }
    if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
      return 'dark'
    } else {
      return 'light'
    }
  })();

  if (theme === 'light') {
    document.documentElement.classList.remove('dark')
  } else {
    document.documentElement.classList.add('dark')
  }

  localStorage.setItem('theme', theme)

  const handleToggleClick = () => {
    const element = document.documentElement
    element.classList.toggle('dark')

    const isDark = element.classList.contains('dark')
    localStorage.setItem('theme', isDark ? 'dark' : 'light')
  }

  document.getElementById('theme-toggle')?.addEventListener('click', handleToggleClick)
</script>

Next, I began working on the index page, and I wanted it to take all of the blog posts and display them in a grid. In order to do this, I was going to need to set up a collection of blog posts.

Blog Posts

I started by creating a mock blog post at src/blog/mock.md. In this file, I also set up the frontmatter schema for the blog posts.

MD Schema

Afterwards, I whipped up a really simple frontmatter schema, so every MD file has its own metadata.

<!-- [post-slug].md -->
---
title: 'This is a title'
pubDate: 2025-06-21
pubTime: 10:00
description: 'This is a description'
author: 'Yours, truly'
tags: ['blog', 'web-dev']
image: 'image url'
---
<!-- Blog Post Content -->

Collection

I created a collection of blog posts in src/content.config.ts, which loads all of the blog posts in the src/blog directory, using Astro’s defineCollection function and glob loader.

In the index page, I was able to use the getCollection function to get all of the blog posts, and then I was able to display them in a grid.

Blog Page

I created a new astro file at src/pages/[...slug].astro: a dynamic route that will render the blog post content. It uses the same getCollection function to get the blog post, and then it renders the content of the MD file.

Layout

Aside from the main <Layout /> component, I added some other content to the page detailing the blog post’s metadata. The layout was generated by v0, since I’m not that great at frontend design. At the bottom of the page, I added a list of all related blog posts, which are posts sharing any tags with the current post.

Rendering Blog Posts

Since Astro already has a way to render markdown built in, all I had to do was render the content of the MD file and pass it to the page layout:

---
// [...slug].astro

const { blog } = Astro.props
const { Content } = await render(blog)
---

<div class="p-4">
  <div class="prose dark:prose-invert">
    <Content />
  </div>
</div>

Styling

Since I used Tailwind for styling, all I had to do was add the .prose class to the container of the <Content /> component and Tailwind styled the markdown automatically.

Tags

I added a page at src/pages/tags/[tag].astro, which lists all of the blog posts that have the given tag. I used the getCollection function to get all of the blog posts, and then I filtered them to only include posts with the given tag.

Adding an About Page

Then, I added an about page to the navbar, and created a matching page at src/pages/about.astro. I just filled this page in with some basic information about me and this blog.

What’s Next?

I plan to keep up with this project, updating it when necessary. I’m also planning on adding more posts over time, with the next post being about Open3 Chat, my submission to the T3 Chat Cloneathon.

Thanks for reading my first ever blog post. I’ve never written a blog post before, so I’m not sure how it turned out. Any feedback is welcome, and you can contact me on X with the link below.

Related Articles

More articles coming soon...