Tools for Building on the Web

April 13, 2025

My hobby projects always devolve into discovering and customizing tools. They start with a clear vision, but the tools are so much more fun. I get sucked in. Just me? Probably not. I'm sure there's more of us nuts out there.

This post is about all the lovely tools I've found along the way with a focus on web development.

Gatsby

Gatsby is a hidden gem, a powerhouse of a framework that's often overlooked compared to Next.js. You'd be forgiven for mistaking it for a static site generator, but that's a niche, not the full story.

Gatsby server-side renders all your React code, chunks it by route for tiny bundles, then hydrates it on load. You get incredible performance. For a lot of the stuff I'm building, I don't need React, but it sure makes life easier. The ecosystem is just too big to ignore. With server-side rendering I barely pay the cost.

The killer features happen at compile time. It has a neat model for running custom code in the build process and safely exposing it to any part of the application, both on the server side and at runtime. There's a ton of plugins ranging from image optimization to markdown parsing to RSS feeds. You can pull files from the web, inject commit hashes, generate pages from data, anything you can want. It doesn't get in your way.

Other things I appreciate:

  • It's stable. Gatsby is a grandpa in JavaScript years. You're not rewriting every week for a new major version.
  • It's focused. It doesn't try to be everything. It works out of the box, you can extend it, but it doesn't force ideas on you.
  • GraphQL. This was weird at first, but they nailed it. While other tools are shoving build data into env vars, Gatsby's method is composable, explorable, type-safe, and pretty easy to extend.

So give it a try. You might be surprised.

Fontsource

The wisdom of eons past recommended loading fonts through independent CDNs so clients could benefit from a shared cache. Modern sandboxing requirements ruined it. CDNs aren't ideal for privacy either, since users send requests to third parties who have every incentive to track them.

Modern approaches bundle fonts with your app, but it's a pain to manage. Google Fonts isn't a complete collection. You need to add a new variant or weight; where did you find the font? Do you store assets in your repository? What about versioning? Are you certain the new variant supports the same glyphs as the others?

Fontsource solves every one of those pain points. Each font is an npm package. As long as you have a CSS loader, it just works.

import '@fontsource-variable/inter';

Vanilla Extract

Vanilla Extract is a CSS-in-TypeScript library with an emphasis on compile-time optimization. You get incredibly efficient classes that only load when you use them.

export const title = style({
fontSize: '2rem',
fontWeight: 'bold',
color: 'rebeccapurple',
});

At first, coming from styled-components and emotion I wasn't sold on the object style syntax. I quickly got on board after using LSP renames, rich autocomplete, and catching invalid rules at compile time. It didn't take long before it felt natural.

You might even find yourself writing more maintainable CSS. It encourages good patterns applicable for any CSS tool.

React Icons

A rather well-known library for icons of all varieties. It contains classics like FontAwesome and Material Icons as well as some more obscure ones. All the icons are SVGs and are tree-shakeable, so you only bundle what you use.

import { WiDaySunny } from 'react-icons/wi';
<WiDaySunny />

It's like having a whole design department just for your hobby project.

Mend Renovate

Renovate is like GitHub's Dependabot but it doesn't suck. It notices when new versions of a dependency come out and automatically creates a pull request. I live dangerously so if it compiles and tests pass, it's configured to auto-merge. (Although I still manually review production deps.)

It's got a nice free tier and supports public and private repos. Here's what my typical config looks like:

{
"extends": ["config:base", ":disableDependencyDashboard"],
"packageRules": [
{
"matchDepTypes": ["devDependencies"],
"automerge": true
}
]
}

If you've ever felt the pain of revisiting a project after a few months only to waste hours updating dependencies, check it out.

Cloudflare Workers

I'll be honest, I'm still waiting for the shoe to drop. This service is suspiciously good. It's fast, easy, and free unless you're driving serious scale. I use it for static site hosting. They have a GitHub Action that makes it pretty easy.

Sometimes I want a little server logic and I'm too cheap to pay for a dedicated host. AWS Lambda functions are a massive pain and carry surprise costs. It's a big time investment for a hobby project that only keeps my interest for a weekend.

With workers, I just slap in a JavaScript file and it works. No noticeable function warmup. They support secrets, object stores, a SQLite database, step functions, containers, and other goodies, but I rarely need those.

I'm anxious putting so much code in a single vendor. Monoliths are harder to replace. On the other hand there's very little code to migrate because there's very little setup, and the rest is hardly specific to Cloudflare. It doesn't tangle itself like other providers.

What keeps me on the platform is the good defaults. I don't have to waste time configuring a million things. I just write code and it works.

Summary

So that's my web stack. I'm pretty happy with it. You can find a complete list of my recommendations here.

If there's an indispensable tool on your list that isn't on mine, toot me on mastodon or matrix. I'm always looking for new toys.