# I migrated my blog from Next.js to Astro

> Next.js was overkill, and Strapi meant constant clicking around the UI. I moved the blog to Astro and Cloudflare, posts live in the repo as MDX, infrastructure in OpenTofu, and Lighthouse shows 100/100.

- URL: https://buildandmarket.dev/en/blog/migrating-from-nextjs-to-astro
- Author: Franek Wojtas
- Published: 2026-09-26
- Language: en

Hey there!

Long time no see. Did you miss me?

So yeah, just like the title says. My blog originally ran on Next.js hosted on Vercel, with Strapi CMS hosted on Railway. But after a while I figured it wasn't the best setup. That's why I decided to migrate the blog to [Astro](https://astro.build/) without a dedicated CMS. If you want to read about why I picked Next.js and Strapi in the first place, check out my previous post on [how I created a blog in Next.js and Strapi](https://buildandmarket.dev/en/blog/how-i-created-a-blog-in-next-js).

## Why did I move away from Next.js and Strapi?

I have nothing against Next.js. I still think it's a great framework. But in my case Next.js was a bit of an overkill. My blog doesn't need most of the features Next.js offers. That's why I decided to migrate the blog to Astro, which is lighter and a better fit for this kind of project. Next.js ships quite a lot of JS to the browser, and I don't need that. I want my blog to be fast and light, so Astro is the better choice.

Then there's the CMS. This project was my first time using Strapi. Overall a pretty decent CMS, but not for me. I'm not a big fan of clicking around the UI. Every change, every new post meant logging into Strapi and clicking around. It's way more convenient to have everything in one place, which means the repo. I was writing posts in Markdown in Strapi anyway, so why would I need a CMS? Locally I can just fire up the dev server and test everything right away, while in Strapi setting up live preview required extra configuration. And then there's maintaining two separate projects. More work with updates, two separate apps to look after, extra hosting costs. And now? Everything in one place, one project, one hosting, [static posts](https://buildandmarket.dev/en/glossary/ssg) in Markdown that I can edit in VS Code. Simple and convenient.

## Hosting on Cloudflare instead of Vercel

In the new version I moved the blog to Cloudflare. The main reason was the hosting cost, and since I already had the domain and R2 on Cloudflare anyway, that was a nice bonus. I wrote a simple CI/CD that deploys a new version of the blog with Cloudflare Wrangler after a PR gets merged. Nothing fancy, but very convenient (Vercel had that too). For a moment I also wanted to add a staging environment on a subdomain, but luckily I quickly realized that for a blog I build on my own it's definitely overkill. I had to click a few things in the UI, and as I mentioned before, I'm not the biggest fan of that. So in a flash of inspiration I decided to add infrastructure as code, which fits my case perfectly. And the choice fell on OpenTofu.

### Infrastructure as code with OpenTofu

[OpenTofu](https://opentofu.org/), my pick for IaC. For the uninitiated, it's a fork of Terraform that was created in response to Terraform's license change. This tool lets you configure environments and settings on platforms like Cloudflare or AWS. Everything you can click through in the UI can be configured in code. A dream come true. For the blog the configuration is pretty simple, no fancy bells and whistles, but it's super convenient. Whenever something changes, you just add a tiny bit of code, run a few commands and you're done. Zero clicking around the UI.

```hcl
resource "cloudflare_workers_custom_domain" "production" {
  account_id = var.account_id
  zone_id    = var.zone_id
  hostname   = "buildandmarket.dev"
  service    = "buildandmarket"
}
```

## Performance after the migration: 100/100 in Lighthouse

Astro is known for shipping minimal JS to the browser, so it's no surprise that the blog flies. Without much effort, Lighthouse showed 100/100 across the board. On top of that there are static files and Cloudflare caching, so the blog has no choice but to fly.

Now all that's left is the most important part of the blog: writing posts.
