Building a Scalable Website with Qwik, Bun and Notion

Building a Scalable Website with Qwik, Bun and Notion

Published:

I rebuilt my website. From a development perspective, I was quite satisfied with the solution of my old implementation. But why did I see the need to throw it over board? This article is a reflection of this decision. Maybe, you can gain some insights as well.

Cover image

When I built my “old” website in 2022, I chose a simple tool stack. It was a Single Page App, based on Lit . There was no backend, and all assets were served by an Nginx server. The content was written in Markdown files. I basically had built my own SSG on top of Vite. I used this stack for about a year, before I decided to rebuild it from scratch in Q4 of 2023.

What are my concerns with the old stack?

Let’s start by collecting some issues I saw with my simple Lit stack.

Performance

First, There is the performance aspect. I am aiming to build more and more features into my website. If you do this with an SPA, you need to do code splitting to have reasonably good load times.

In traditional component frameworks, and also in Lit, you usually do this via dynamic imports.

But hydration still has to happen, before the page is interactive.

And this has a negative impact on the SEO score.

SSG vs. SSR

Second, with the Static-Site-Generator (SSG) approach, I would always have to rebuild the application and redeploy the docker image on every content change.

This leads to more CI pipeline runs and downtimes during deployment.

In a Server-Side-Rendering SSR (SSR) environment, the HTML is generated on-demand with the current underlying content. This means more cost per request, but no need to rebuild and redeploy, if the content is updated by the upstream data source. The rendered result can then still be cached on the edge and on reverse proxies to reduce rendering cost.

Scalability

Third, I want my stack to be able to scale.

If the content is burned into the application at build time, it needs at least Markdown know-how and some operation effort to fork a new application.

What does the new stack look like?

My new stack consists out of Qwik , Bun , SQLite and Notion .

Qwik runs in SSR mode. Bun with SQLite hold some pre-processed content, which is synchronized with Notion. Notion serves as my CMS.

This stack solves all the problems listed above.

Resumability with Qwik

Qwik has a new approach to SSR. It is called “resumability”. Instead of rendering a page twice — On the server (SSR) and on the client (hydration) — it is rendered once on the server and state and listeners are serialized to the HTML. I explained this in more detail in my post 4 Reasons Why I'm Buying Into Qwik

As a result, resumability minimizes the Time to Interactive because, by default, very little to no JavaScript is executed on page load.

Code-splitting is done every time, you see a trailing $ sign in Qwik. So the code is split into tiny modules, containing single callbacks. Those modules are interpreted just in time before they are executed. And they may be prefetched by a service worker to reduce network latency when the modules are actually required.

Pages built with Qwik are likely to have a great lighthouse performance score.

So with Qwik we can build complex websites and web applications, without sacrificing performance. And as a nice bonus, we get to choose whether we want to have an SPA or MPA experience on every navigation step.

Content service with Bun and SQLite

I decided to create a content service with Bun. The reasons why I picked Bun are primarily performance paired with a great development experience. I go into more detail about this in Should You Use Bun In 2024?

This content service is meant to be a caching proxy to an upstream CMS, which currently happens to be Notion. It basically optimizes access times and transforms the content data into a simpler, CMS-agnostic format.

This also makes switches between CMS systems easier, just in case I decided to go away from Notion, one day.

The database is a simple SQLite instance. Since the single source of truth is the CMS, scaling the DBs would be trivial by just replicating the service and synchronizing those replicas directly with the CMS.

Notion as a CMS

I am not very experienced with CMS systems, but I’m sure that there are plenty of great options. For now, I’ll stick to Notion because it is free, has a great writing experience and a reasonable API.

It is also a SaaS solution, where everyone can easily join projects. It is also simple, so there is no big onboarding process. This makes it a perfect choice for collaboration or for providing basic web development as a service.

Conclusion

I am quite satisfied with my new tool stack. It solves all the problems that I faced with my previous SSG solution: It provides great performance, fewer downtimes and scalability.

Maybe, you could gain some inspiration for your next web project.

Never stop learning and happy coding!