← Back to all posts
Engineering

Building This Blog with Astro on Cloudflare Pages

Zero to live: a free, blazing-fast, low-maintenance setup for a personal blog.

The blog you’re reading was built with exactly the method in this post. The setup has only three goals: fast, cheap, easy to maintain.

Why Astro

There are plenty of blogging frameworks. I landed on Astro for simple reasons:

  • Zero JavaScript by default. A post page is essentially static HTML — the browser doesn’t have to run a pile of framework code before showing you a paragraph of text.
  • Markdown as a first-class citizen. Content collections manage posts and even type-check the frontmatter.
  • Component-based without holding you hostage. .astro components read like HTML; bring in React or Vue only if you need them.

Up and running in three steps

# 1. Create the project
npm create astro@latest my-blog

# 2. Preview locally
cd my-blog && npm run dev

# 3. Build the static files
npm run build   # output lands in dist/

Posts are written in Markdown and dropped into src/content/blog/. A content collection definition looks roughly like this:

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

const blog = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
  schema: z.object({
    title: z.string(),
    pubDate: z.coerce.date(),
    category: z.enum(['tech', 'ai', 'essay']),
  }),
});

export const collections = { blog };

The schema validates every post’s frontmatter at build time — a typo’d field fails the build, which beats discovering it after you’ve shipped.

Deploying to Cloudflare Pages

Cloudflare Pages is effectively free for static sites, with a global CDN and very low latency. Two ways to deploy:

  1. Connect a Git repo (recommended). In Pages, pick the repo, set the build command to npm run build and the output directory to dist. Every git push deploys automatically.
  2. Direct upload. Run npm run build locally, then push the output with wrangler pages deploy dist.

It comes down to one line: build command npm run build, output directory dist. Cloudflare handles the rest.

Squeezing out a bit more speed

  • Set max-age=31536000, immutable on hashed assets like /_astro/* so the browser caches them forever.
  • Use a system font stack to skip the wait on web fonts.
  • Run images through Astro’s <Image /> component for automatic compression.

Put it together and a perfect Lighthouse score comes easily — while your monthly bill is exactly zero.