Migrating to SSR and source availability

matt

My blog is actually two applications: a frontend and a backend. The frontend used to be a client side rendered (CSR) application, which worked fine for my usual work on internal tools. But when I wanted link unfurls on platforms like Discord and Slack, I realized I needed to switch to server side rendering (SSR).

Why CSR Wasn't Enough

CSR apps are fast to develop and easy to deploy. The browser loads a minimal HTML file, grabs a JavaScript bundle, and builds everything from there. For internal dashboards? Perfect.

But for public-facing content where metadata matters—like link previews—CSR just doesn't cut it.

Here's what a typical CSR request looks like:

Slack and Discord bots aren’t going to run your JavaScript to extract meta tags. They just want the HTML as-is.

The Big Switch: Nuxt

So I moved my frontend to Nuxt which is more purpose built for SSR applications. For the most part it feels just like Vue + Vite.

This wasn’t just a framework swap, though. It meant rethinking my whole authentication setup.

localStorage, Meet Server

In the CSR world, I stored authentication tokens in localStorage. It’s simple:

localStorage.setItem('access_token', token)

But SSR means the server is responsible for rendering pages. And guess what? Servers can't access your localStorage.

The Problem

So I had to refactor my auth to use HTTP cookies, which are shared with the server via headers.

GET /dashboard
Cookie: access_token=abc123

It’s a more complex setup (and yes, secure cookies with HTTP-only flags and proper domain scoping are a thing I had to think about.)

Side Effects and Downtime

This migration wasn't without casualties:

I worked through the bugs with the help of Cursor, and things are stable now. I'm even reaping the benefits:

Oh, and the Source is Available

Now that things are working, I'm also using this moment to make my project source available. There's no license on it (yet?)—so feel free to browse, peek, and maybe file an issue if you’re feeling generous. The main reason I'm doing this is so that other people can see how I'm leveraging and using LLMs on a codebase.

Back to top