Building an easy on the eyes IKEA style blog, in no time, for free, again

It’s been over a year since I bought a new domain and redesigned my blog. I wrote a post about Medium and why I decided to stop writing there. I was planning to write about many things, I set up a nice Markdown editor on my Mac, everything was ready to go. Then I did nothing, for a year. 😴

During this lockdown, I felt the urge to do it all over again but I successfully resisted it. Then I caved in one evening and rebuilt everything. This time it’s much simpler and I’m much more pleased with the tech stack.

The future is (NextJS) static

I’m happy to say this blog is built with NextJS which is one of the best and most polished pieces of software I’ve ever used. I don’t say this lightly as I’ve been a huge Gatsby fan and I still am.

Not long ago I was suggesting people to use Gatsby for almost any kind of site. Probably the only exceptions were complex client-only apps and sites with tens of thousands of unique URLs. Still, I was constantly being dragged to NextJS as it could easily handle any amount of pages. I haven’t dwelled too much on it though, it couldn’t generate pages during build time, and that bugged me.

Oh, how the tables have turned! The last two NextJS releases were 🔥. I’ve closely followed the discussion in the SSG PR almost since it appeared. Now NextJS can generate pages during the build, and not only that, but you can also set it up to render some of those pages on demand. 🤯 There’s more, they’ve recently shipped unstable-revalidate option that allows you to refresh pages even though they were rendered during the build.

I’m pretty sure I won’t be going back to Gatsby any time soon. I was always uncertain about their GraphQL data ingestion API. In some ways, I do like it (when it works). Nonetheless, it’s not easy to debug something if a plugin doesn’t work properly. Choosing between static, page, or build time queries to load data feels like arcane art when you have a lot of data to pull. In my experience, the only bearable approach was to load everything in gatsby-node.js and then pass it to pages. Maybe I’ll cover that in another post.


I’m used to Contentful. I’ve worked with it both for my projects and at work. It might be one of the best headless CMSs out there. It’s super easy to set up a new space and create content. It supports webhooks for any kind of content update. It took me 3 minutes to set up rebuilding on Vercel every time the content changes.

The major game-changer was the Preview API. I was expecting a lot more hassle to set it up but the NextJS guides were fantastic and straightforward. It probably took me around 10 minutes. Having the ability to see content changes almost in real-time is amazing!


This blog is super simple. The index page is static, generated during the build. I might enable fallback on it. Since the CMS triggers a rebuild on every change, I’m not sure if it wouldn’t make a huge difference.

The posts are static too but they have the fallback option enabled, along with the unstable_revalidate. This allows them to be regenerated on demand. This is a huge thing for me as it’s doing wonders for previewing unpublished posts.


I discovered a cool plugin next-seo that allowed me to set up SEO related stuff in no time. Setting up opengraph data is a breeze. It even has predefined components for some common JSON+LD types so now my blog has that too.

It took me some time to figure out how to set up a robots.txt but in the end, I just needed to put it in the public/ directory.

The sitemap was a different story. I was expecting there would be a plugin of some sort. I first tried making an API endpoint that builds and serves the XML. That was working fine but there was no way I could make it available at /sitemap.xml. The solution was to “hack” the sitemap.xml.js page’s getServerSideProps to generate and respond with the XML by using the res inside the context (argument of the function).

The sitemap is generated by the sitemap package.


I added a feed too. That was straightforward after dealing with the sitemap as I made an API endpoint that generates and serves it. I used the rss package even though its API is somewhat weird. It uses streams to improve the responsiveness. However, I expected a simple “bulk” option which is not available.


I think it was never easier to build something on the web. It amazes me how much complexity has been successfully hidden under the hood. All the parts just fit together.

Even though I wrote this from scratch I spent almost no time on CI/CD, previewing, SEO, and performance. It’s like shopping for unassembled products at IKEA and still ending up with an interesting room with unique character.

The IKEA effect is simple: when you work for something you fall in love with it.

One could argue there are simpler ways to build a blog, and to be honest I did look into Zola. Even though those kinds of generators don’t have React as a dependency and generally produce even smaller pages, the editing process cannot be compared to what I have now.

I haven’t even thought about performance yet but I’ll just leave this screenshot here.

performance audit

The “Best practices” section is complaining about a few NextJS preloading errors in the console. This one is basically a 100 too.

Visually, this blog is almost entirely inspired by the minimal design of, the blog of Guillermo Rauch, CEO of Vercel. Even though it’s open-source I wanted to build mine from scratch. In the end, I opted for a similar “timeless” design.

Let me know if you’d like me to cover something specific in detail. I haven’t got a subscription form yet, but you can follow me on Twitter (link at the top 👆).