Skip to content
← Blog

Building a Modern Personal Blog with Astro and Cloudflare Pages

• 5 min read
astrocloudflaredevopsweb-performance

I finally got around to rebuilding my blog. The old setup worked, but I wanted something faster and easier to maintain. I have been looking at Astro for a while, I heard many positive things about it, so I decided to give it a try.

Since I’m a big fan of the Markdown format, and I really enjoy writting content in it, Astro seemed like a great fit. I also wanted to automate things as much as possible, so from the infrastructure to the deployment process, everything is written as code and automated.

Why Astro?

As mentioned, I wanted to write content in Markdown but why choose Astro over the other tools? I researched a lot of static site generators before settlign with Astro, I really like to read people’s experiences and opinions on different tools. From what I have seen, people had a pleasant experience with Astro. The development experience seemed quite smooth, performance was great, community and developers are very active. I read the docs, tried a few tutorials and I was sold, DX was great and this felt like the right tool for the job.

I really like that I could also define content collections natively using Zod for schema validation, so frontmatter is type-checked:

const blog = defineCollection({
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.coerce.date(),
    tags: z.array(z.string()).optional(),
  }),
});

Astro have also a zero-JS approach, so by default no JavaScript is shipped to the client unless explicitly added. Creating a simple blog site without client-side interactivity is very straightforward. This results in a very fast site with minimal setup.

Cloudflare Pages

I’m using Cloudflare Pages for hosting. It’s free, has a global CDN, and connects directly to GitHub. When I push to main, and the site rebuilds automatically.

I also prefer to manage infrastructure as code. Currently using OpenTofu (a Terraform fork), I can easily define the CloudFlare Pages project:

resource "cloudflare_pages_project" "paulocurado-website" {
  account_id        = var.account_id
  name              = "paulocurado-website"
  production_branch = "main"

  source = {
    type = "github"
    config = {
      owner             = "phcurado"
      repo_name         = "personal-website"
      production_branch = "main"
    }
  }
}

and running tofu apply provisions the project to CloudFlare infrastructure.

There are more resources that I manage via Terraform, but this is the main one for the Pages site. I can easily add other sites with this setup, and everything stays consistent on git.

Automated Quality Checks

I added GitHub Actions to catch problems before merging. The workflow runs ESLint, Prettier, and Vitest on every PR. If lint fails, the PR is blocked.

But the interesting part is Lighthouse CI. Every PR gets a full Lighthouse audit:

{
  "assert": {
    "assertions": {
      "categories:accessibility": ["error", { "minScore": 0.9 }],
      "categories:seo": ["error", { "minScore": 0.9 }]
    }
  }
}

If accessibility or SEO scores drop below 90%, the PR fails.

This helped me to caught some bugs. On the first run, Lighthouse complained about:

  • The theme toggle checkbox not having an aria-label
  • Links that relied only on color to be distinguishable
  • Insufficient color contrast on badge components

I’m not a frontend developer by any means, so having these checks in place is very helpful. It forces me to think about accessibility and SEO from the start.

Preview Deployments

Every PR gets an automatic preview deployment from Cloudflare. The bot comments with a link:

Preview URL: https://branch-name.paulocurado-website.pages.dev

Altought I’m not super strict about checking the preview on every PR, it’s nice to have the option. Sometimes I just want to see how something looks live without merging to main.

Setup Summary

Lighthouse CI is worth the setup time. It’s not just about only catching bugs but also forces you to care about accessibility from the start. When your PR fails because a link doesn’t have enough contrast, you fix it. Otherwise I would be ignoring these issues, and only cought once I decided to run lighthouse or paste my site in google pagespeed to get insights.

Preview deployments is very nice to have. Being able to click a link and see your changes live is faster than running a local dev server, more reliable than the local machine, and great for sharing with others.

Astro’s zero-JS approach is very interesting for my use case since, most likely that majority of simple sites don’t need client-side rendering. I don’t like the current state of the heavyweight JavaScript frameworks like NextJS, this is a simple blog after all so I don’t need complex setups.

Infrastructure as code pays off immediately. When something breaks, I don’t need to remember what I clicked in a dashboard. I look at the Terraform file, see what’s deployed and fix it.

Conclusion

Building a personal blog in 2025, with these tools are great user experience. It’s fast, accessible, and easy to maintain.

You don’t need to automate like I did, but you will benefit in future when you haven’t touched the site in months and need to make a change, you get: Lighthouse CI, linting, and tests catch issues before they reach production, preview deployments and complete infrastructure as code.

If you’re thinking about starting a blog, I’d highly recommend this stack. It’s fast, free and works really well.