Benji Riethmeier
Icon

Building a Blog With Astro 2 (Instead of Next.js)

5/18/2023 | 11 min read

These days, there are many options and tools to build a developer blog.

Should you use a back end content management platform like Contentful or Sanity , or should you just write everything in Markdown or MDX ?

For the frontend, should you use Remix, Next, Gatsby, Astro, 11ty, SvelteKit, or something else entirely?

Is WordPress still an option?

Of course, the short answer is going to be: it depends. It depends on your priorities and what you want your blog to be able to do.

For myself, I wanted to be able to have as much flexibility as I possibly could so that I could have the exact style that I want for each post as well as the ability to incorporate custom components. I would also like my site to have good Core Web Vitals and SEO.

But why consider making a blog at all?

Why a Dev Blog

While I’ve always loved writing, I created this blog initially to host blog posts that I had to create for school. In my senior year of college, I worked on a team that was creating a sports statistics mobile app called Courtside for my senior project course (read more about my experience developing for Courtside !)

One of the major assignments in the class was writing a weekly devlog about the work you did on the app that week. While these blog posts could just be submitted as a block of text to our professor, I decided to create a blog website as a fun side project.

At first, I just wanted my blog to host these progress reports, but now that my senior project is done, I want to expand to write about anything that I’m learning in the field of software development and computer science.

How I Built My Blog

Originally with Next.js

When I first created my blog, I used Next.js. This allowed me to use a framework that I was comfortable with and experienced with. A big benefit of using Next.js was the huge ecosystem of packages that it could plug into via React.

This gave me lots of choice when it came to finding a package to use for MDX integration. Next.js has its own MDX integration, but there were other options such as mdx-bundler. I ended up using mdx-bundler since it made the most sense to me. However, this came with the downside of having to create lots of utility functions to manipulate files to get my post data into the app.

For styling in my project, I mostly used Tailwind since that is what I was using at the time. However, I was starting to transition to using CSS Modules instead.

Some features of my project required data fetching, such as keeping track of views on my posts. I used React Query to get that data from the server, and I also experimented with using tRPC .

However, Next.js is ultimately a really heavy framework for a developer blog, even with all the customization and control I want to have over my blog posts. The framework has to ship a large amount of JavaScript to the client, resulting in worse performance. So while Next.js is stellar for a huge and complex web application, I had a feeling that my blog could be better served by a different framework.

How About Astro

I decided to transition my blog to Astro even though my blog website is still young. Why would I do such a thing? A few reasons.

For a developer blog, Astro almost seems built specifically for this use case.

The Basics

Astro projects are mostly made up of .astro components. These components have two parts: a component script and the component template.

---
// this is the component script
//write any js or ts you like here and it will run only on the server

// component props are handled here!
const { text } = Astro.props;
---

<!-- this is the component template -->
<!-- write your html here -->
<p>{text}</p>

<!-- add style tags for styles -->
<style>
	p {
		color: red;
	}
</style>

<!-- add script tags for scripts you want run on the client -->
<script />

These components can even include components from other frameworks as children, but I’ll talk more about that later.

You include these components in pages, which are kept in a reserved directory called pages i.e., the same as it is in Next.

You can even create API endpoints in the pages directory by adding .js or .ts files.

Built-In Features

Astro has many built-in features designed to create developer blogs. Astro packages make it easy to create an RSS feed and a Sitemap .

Syntax highlighting is also built into Markdown, such that any code within three backticks is automatically syntax highlighted. You can choose between using Prism or Shiki (your choice in the configuration file.) * There are also <Code /> and <Prism /> components for use outside of Markdown.

Content Collections

There are also content collections , which help to organize different types of content and even validate the front matter of each markdown (or MDX) file via TypeScript. Astro also provides different methods that can query markdown files in content collections.

import { getCollection, getEntryBySlug } from 'astro:content';

// get all posts in the 'blog' collection
const all = await getCollection('blog');

// get one post about the astro migration
const astroMigrationPost = await getEntryBySlug('blog', 'astro-migration');

// filter posts to return posts about react
const reactPosts = await getCollection('blog', ({ data }) => {
	return data.tags.includes('react');
});

Having these methods built-in completely removes the need for all the utility functions I had to home bake to connect my post MDX files to Next.js and mdx-bundler for use in the app.

These different methods return an object with a few different fields, including:

  • slug: the slug of the file
  • data: the front matter of the file
  • render: a method that creates HTML from the provided content

The render method returns a <Content /> element, which can be placed in the HTML. However, this method also returns a headings object which lists all the headings in the markdown as well as the depth of each heading (depth of 2 is an <h2 /> element.) This makes it trivial to create a Table of Contents for your posts. You can see mine on the right side of the article if your screen is large enough!

Performance

Speaking to that last point about Next.js being heavy duty and using a lot of JavaScript, Astro does the opposite by default. JavaScript is opt-in. It does this by using an Island Architecture , where there are islands of interactive content within the website while everything around it is static.

Since my blog is mostly static and only occasionally requires interactive components with JavaScript, Astro once again proves to be perfect for my use case.

But when I do need interactivity (e.g., I want to add a cool custom component to my blog), how can I do so?

If you are just using vanilla JavaScript, you can provide some <script /> tags, and you are ready to go. However, if you want to use your favorite framework (e.g., React, Svelte, etc.), you can do so with Astro’s integration system.

Integrations

Astro provides many integrations to give Astro to allow it to work with other frameworks and libraries. These integrations can bring in anything from CSS frameworks like tailwind (@astrojs/tailwind ) to SSR adapters like Vercel or Netlify (@astrojs/vercel ) to JavaScript frameworks like React (@astrojs/react ).

These integrations can be added easily with a simple command:

npx astro add react

This will do all the setup and configuration, allowing you to start writing React components in Astro immediately.

For my blog, I deploy on Vercel and I also have a few components written in React. The framework integrations are especially nice because framework components (e.g., React, Svelte, Lit, etc.) can be placed into regular static Astro components.

The framework will be sent to the client along with the component code whenever the component needs to be hydrated, i.e., unless you specify, the framework will not be sent before the page loads * If you have multiple components from the same framework, the framework is only sent once. .

I enjoy this because it removes the largest downside of UI frameworks: that the webpage cannot load before the framework is sent to the client, resulting in slower load times (especially true for React).

These integrations also easily allows me to experiment and play around with different frameworks for different parts of the app. This means I can contineu learning and tryign new things without having to spin up a whole new project.

Developer Experience (Mostly Vite)

Another amazing thing about using Astro over Next.js is an improved developer experience. In my experience, this comes both from all the built-in features mentioned above, and the use of Vite instead of Webpack.

In development mode, Vite sets up on localhost so much faster than webpack ever did, even for a brand new empty website. This also results in a much faster build process on Vercel.

The use of Vite also gives your site access to a huge community of Vite plugins, Rollup plugins, and esbuild plugins to help make your website run.

The Unfinished Bits of Astro

For the most part, Astro has been working phenominally for my blog. However, I do have a few grips with it as well as a few thigns I miss from Next.js. For the most part though, these things are here because Astro is still a young framework and will hopefully improve with time.

Images

While Next.js provides one system for images, which uses the public directory and the <Image /> component, Astro currently provides two different systems.

The first system works much like Next.js with the public directory and <Image /> component. Astro even has the added benefit of allowing image syntax in Markdown to directly connect to the public directory.

<!-- gets image from /public/assets/picture1.jpg -->
![This text is the alt text](/assets/picture1.jpg)

<!-- gets image from the same location -->
<img src="/assets/picture1.jpg" alt="The alt text" />

This first system also allowed me to easily transfer my images from my initial Next.js blog into Astro.

However, Astro also currently has an experimental second system called assets.

The experimental assets feature has you provide your images in the /src/assets folder and then provides optimization for images in that folder. This feature also comes with its own <Image /> component. Assets are well integrated with Markdown and Content Collections.

However, having two systems with two different image components makes the API confusing. Even more so while the assets API is still experimental and subject to change.

While I currently use both systems in my blog, I plan to eventually transfer all images over to the assets API.

Ultimately, I think the assets API is very promising and will help streamline the use of images, but for now it is a bit of a mess.

OG Images

Yes, we are still on the images. One of the nice features provided to NExt.js by Vercel is its OG image generation package. I used this package to create post thumbnails for my Courtside Devlogs. However, Vercel’s image generation did not play very well with Astro.

This resulted in me having to create a home built OG Image generation system. I followed a great tutorial by a developer named Rumann to get mine setup.

The setup is not actually that difficult, but it was convenient to have an easy-to-setup OG image generation system with Next.js.

Code Block Customization

Having built-in syntax highlighting is quite convenient for building a developer blog. However, I have not yet found a way to easily customize them yet.

const dummyFunction = (text: string) => {
	console.log("This is that text: ", text);
}

As of now, the code blocks on my site don’t have any extra features such as a button to copy the code within the block. They also don’t have any extra information such as a built-in heading for the code block or a label for what programming language a block is in.

Since Astro’s documentation site uses Astro itself, I may have to look inside their repository to see how they customize their code blocks.

Conclusions

Overall, I love using Astro for my blog website. It has so many useful features baked in, provides a better developer experience via Vite, and gives better performance for end users.

The framework does still have some shortcomings when compared to the fully fleshed framework that is Next.js, but I believe these will be addressed with time. With the release of Astro 2.0, the development team has shown that they are willing to take leaps and bounds to continue to improve the framework, and make it the best framewokr for content focused sites.

I’m very excited to watch this framework continue to grow and how it can continue to improve my blog!