1 min read

How this blog is built

Markdown files in a Git repo, built with Astro and served from S3 and CloudFront.

This blog is a folder of Markdown files. Publishing a post means pushing a commit. There’s no CMS, no database, and no server to keep running.

A push to GitHub triggers GitHub Actions, which builds the site with Astro, uploads it to a private S3 bucket, and CloudFront serves it to readers.

The pieces

  • Astro turns Markdown into static HTML at build time. Pages ship with no JavaScript.
  • GitHub Actions builds the site on every push to main and uploads the output.
  • S3 stores the files in a private bucket. Nothing reads from it directly.
  • CloudFront serves the site over HTTPS from edge locations and caches everything it can.

Writing a post

Each post is a folder. The folder name becomes the URL, and images live next to the text that uses them:

src/content/posts/
  how-this-blog-is-built/
    index.md
    pipeline.png

The post starts with a few lines of frontmatter:

---
title: How this blog is built
description: One sentence for the post list and link previews.
date: 2026-10-04
---

Images use normal Markdown with a relative path. At build time Astro resizes them, converts them to WebP, and gives each file a content hash in its name, so CloudFront can cache it for a year without serving a stale copy.

Caching

HTML pages are cached at CloudFront until the next deploy clears them, and browsers check for a new version on every visit. Images, fonts, and CSS have hashed file names, so browsers keep them for a year.

← All writing