How I built this site
Next.js 16, tagged caching, two languages and a blueprint design: the decisions behind my new portfolio.
When I started my new portfolio I wanted three things: it should load fast, search engines should see all of the content, and I should be able to update it without touching code. Here is how the site is put together.
Foundation
The site runs on Next.js 16. Pages are generated as plain HTML at build time, so when a visitor or a crawler arrives the server has nothing to compute.
Content (projects, experience, blog posts) lives in a Postgres database. In production that's Neon; on my machine an embedded Postgres (PGlite) starts with zero setup and seeds itself on the first run.
Caching: when does a page refresh?
Every function that reads data is cached and tagged:
export async function getProjects(locale: Locale) {
"use cache";
cacheLife("max");
cacheTag("projects");
return getProjectsUncached(await getDb(), locale);
}
When I update a project, invalidating the projects tag is enough: only the pages that use that data are regenerated, and everything else stays cached.
Design
I wanted a technical-drawing (blueprint) feel: a faint grid, dashed section dividers, a single accent colour and monospace headings. Text is set in Plus Jakarta Sans, code and labels in Geist Mono. The theme follows your system setting, and you can pick light or dark from the header.
Live parts
A few sections change on every visit: my Discord status, what I'm playing on Spotify and my GitHub contribution graph. They load in the browser inside fixed-size boxes so they never slow down the rest of the page; if a service doesn't answer, nothing breaks and the box falls back to a quiet state.
What's next
An admin panel I sign into with Discord, where I'll edit the blog, gallery and projects. Saving will refresh the affected pages immediately.