Moving from Gatsby to Astro

in tech

It’s been a few years, so high time I remade my website! A few years ago, I moved to using Gatsby for this site, but there have been a few things pushing me to move away from it.

Despite being bought by Netlify, Gatsby appears to be in maintenance mode with very few updates being made to it, much less a feature roadmap. Whenever I added a new post, my CI (Github Actions) would complain to me about outdated dependencies, and building a post and deploying took well over two minutes every time.

So having decided to move on from Gatsby, I chose Astro for a few reasons:

Web tech first

The web tech-first approach was a big draw - Gatsby seemed nice at the time where I could use React and Graphql to query data, but it ended up seeming like way too much overhead for not a lot of payoff. Gatsby’s default setup also caused me a few issues, for instance often trying to enable offline tech which did nothing but break unexpectedly for people.

I was always having to think about how to add content to the site, which is really bad for a very simple blog. Astro using web tech, so mainly HTML and CSS, fitted in with my site mainly being static article content.

Rather than thinking about HTML and CSS for layout, I had to work out how Gatsby was expecting it, or convert it into React - eg className, htmlFor rather than the HTML equivalents.

Developer experience

The developer experience of Astro ended up being really nice too. There’s a huge amount of documentation including a getting started guide, so every time I googled “how do I do something in Astro” there was always an official doc page for it.

Astro is also really close to plain HTML, so I don’t have to worry about things like Helmet to put scripts in the right place, like with Gatsby. The other nice trick Astro has is being able to add styles or scripts in a template file, which scopes the CSS or JS to just to that page. That made it incredibly easy to add customised layouts, and meant I could remove a lot of my original CSS framework.

Astro also adds type safety for content, so I can ensure all my posts have the same frontmatter or get warnings if I mis-spell a category name, which fixes a lot of annoying issues I had with Gatsby. Types are defined using Zod, which is nice since I’m familiar with it from work. This even works for things like JSON content, eg the project page on my site, so I can be sure that all my entries are consistent.

Example category typing:

const Category = z.enum([
  "game",
  "rust",
  "javascript",
  "web",
  "react",
  "android",
  "tech",
  "projects",
]);
export type Category = z.infer<typeof Category>;

const BlogSchema = z.object({
  title: z.string(),
  date: z.string(),
  description: z.string(),
  category: Category,
});
export type Post = z.infer<typeof BlogSchema>;
---
catagory: "rsut"   <--- big type error in my IDE for this typo!
---

Some blog post

Island architecture

Astro’s island architecture is really nice. In essence, this means the majority of pages will be static HTML, but you can easily add a little area - or island - of interactivity using React or Svelte or similar. Only the page with the interactive element will load dependencies, keeping the majority of the site lightweight.

As an example, here’s a little Truchet tile generator I wrote to create the background of the site:

Adding this to a blog post is basically a one-liner:

import { Truchet } from "components/Truchet";

Some blog post words.

<Truchet client:load>

Some more words later on.

which makes it incredibly easy to drop fun things into posts. Since the component lives separately to the Markdown post, I can update the component separately without having to update the post again, or manually manage React dependencies in my post content.

Build time

A nice benefit of moving to Astro is that build and deploy times are now incredibly fast compared with the Gatsy build.

Before (Gatsby)After (Astro)
Total CI time2m15s40s
Install1min8s
Build1min11s

Even with a cold start (ie no caching) the Astro install step is less than 10 seconds, compared with Gatsby’s 1 minute - this is sort of to be expected when looking at Astro’s dependencies compared with Gatsby’s. I have dropped Sass for the Astro version which almost certainly takes up a chunk of the install and build time, but there is a huge drop in time spent with Astro.

For the build step, Gatsby is converting all code from React into HTML, as well as converting Graphql queries and fetching and populating data into the HTML. At first glance, Astro’s process is much simpler and lightweight, especially considering most data is already either Markdown or JSON.

As well as being faster to deploy changes, it saves energy (and would save money if I wasn’t on a free CI plan!), which is nice from a sustainability point of view.

Wrapping up

Overall, I really like Astro. It feels simple to use, my site content is in standard HTML, CSS and Markdown for the most part, and it feels similar enough to modern web frameworks like React to be familiar.