How This Blog Is Built: Astro + Markdown + Cloudflare Pages

3 min read
On this page

This post is both an introduction to the blog and its living documentation. If future-me forgets how anything here works, this is the page to read.

The stack

  • Astro — static site generator. Zero JavaScript by default; the only scripts on this site are the theme toggle, mobile menu, copy-code buttons, and search.
  • Markdown content collections — every post is a .md file in src/content/blog/, validated against a schema with Zod.
  • Tailwind CSS v4 — with a small set of CSS variables powering the light/dark themes.
  • Pagefind — fully static search, indexed at build time. No server, no third-party service.
  • Cloudflare Pages — the built dist/ folder is served from Cloudflare’s edge network. There is no runtime at all.

Writing a post

A post is a Markdown file in src/content/blog/. The filename becomes the URL slug, so my-new-post.md is served at /posts/my-new-post/.

---
title: "My New Post"
description: "One or two sentences shown in cards, search and RSS."
pubDatetime: 2026-09-01T10:00:00Z
tags:
  - nodejs
  - tips
---

Content goes here. Regular **Markdown** works, including code blocks
with syntax highlighting.

Frontmatter reference

FieldRequiredNotes
titleyesPost title
descriptionyesUsed in cards, meta tags and RSS
pubDatetimeyesISO date; future dates stay hidden until then
modDatetimenoSet when you edit a published post
tagsnoDefaults to ["others"]
featurednoPins the post to the Featured section on home
draftnotrue = visible in dev, excluded from builds
ogImagenoCustom social image, else /og.png is used
canonicalURLnoIf the post was first published elsewhere

Callouts

Pull a warning or an aside out of the body copy with GitHub-style alert syntax. Five types are available — NOTE, TIP, IMPORTANT, WARNING and CAUTION:

> [!NOTE]
> Useful context that is not essential to the main point.

> [!WARNING] This one has a custom title
> Anything after the marker becomes the heading.

They render like this:

Note

Callouts are plain blockquotes until a remark plugin spots the marker, so they degrade gracefully anywhere else Markdown is read — in your editor, on GitHub, or in the RSS feed.

Tip

Press / or ⌘K anywhere on the site to open search without reaching for the mouse.

Set your site URL before deploying

SITE.website in src/config.ts drives canonical URLs, the sitemap and every Open Graph tag. Publishing with the placeholder in place means search engines index the wrong domain.

Local workflow

npm run dev      # write with live reload at localhost:4321
npm run build    # build + generate the Pagefind search index
npm run preview  # serve the production build locally

Deploying

The site deploys to Cloudflare Pages either from git (push to the production branch and Cloudflare builds it) or directly from the terminal:

npm run deploy   # builds, then `wrangler pages deploy dist`

That’s the whole system. Posts are files, the site is static, and the platform is someone else’s problem — exactly how a personal blog should be.


Share: