The Tech Stack Powering This Portfolio
This portfolio is more than a résumé — it's a living demo of how I think about building things. Here's the complete picture of what it's made of and why.
Framework: Next.js App Router
I chose Next.js 15 with the App Router for a few non-obvious reasons:
- React Server Components by default — most content on a portfolio is static or read-only. RSCs mean zero client-side JavaScript for pages that don't need it.
- File-based routing — simple and predictable.
/blog/[slug]just works. - Incremental adoption — I can opt a single component into client interactivity with
'use client'without refactoring the whole page.
Styling: Tailwind CSS v4
Tailwind v4 dropped the JavaScript config file entirely. Design tokens now live in CSS:
@import 'tailwindcss';
@theme {
--color-bg-deep: #0f1923;
--color-bg-surface: #162232;
--color-accent-coral: #ff6b4a;
--color-text-primary: #f0ede6;
}
This is a massive improvement. Your design system becomes portable — any tool that reads CSS understands it.
TypeScript: Strict Mode
All TypeScript configs point straight to "strict": true. The friction at dev time is worth the confidence at runtime. A few patterns I enforce:
interfaceovertypefor public API shapes- No
any— useunknownand narrow it - Exhaustive
switchwith aneversentinel
function assertNever(x: never): never {
throw new Error(`Unhandled case: ${JSON.stringify(x)}`)
}
Content: Markdown + Gray Matter
The blog section reads .md files directly from the repository using Node's fs module:
gray-matterparses YAML frontmatter into a typed objectremark+remark-htmlconverts the body to safe HTML- A custom
estimateReadTime()function counts words and divides by 200
No database. No CMS. No API. Just files.
Deployment
The site is deployed on Vercel with:
mainbranch → production- Every PR → preview URL
- Zero-config builds (Vercel detects Next.js automatically)
Build time is under 30 seconds. Cold start is under 50 ms.
What I'd Do Differently
Every project has lessons. Mine:
- Start with mobile. I retrofitted responsive styles on two components and it was painful.
- Design tokens first. Define your full palette before writing a single component.
- Commit your
globals.cssearly. It becomes load-bearing faster than you think.
The Source
This portfolio is open source. If something looks useful, fork it — that's what it's there for.