Problem
Wanted a portfolio recruiters could skim in 60 seconds and engineers could dig into for hours — plus a blog I could keep updated without leaving my usual tools. Notion is where my notes already live.
Approach
- 1
Bootstrapped with Next.js 15 App Router + TypeScript + Tailwind, hosted on Vercel. ISR (revalidate=3600) for static-fast rendering with fresh Notion data.
- 2
Wired Notion as a headless CMS via @notionhq/client + notion-to-md, rendering with react-markdown + rehype-highlight so code blocks are syntax-highlighted and every Notion block type is supported.
- 3
Built a /api/revalidate webhook so a GitHub Actions cron (or Notion Automations) can push edits live within minutes — no waiting for the 1h ISR window.
- 4
Server-side fetched GitHub + GeeksforGeeks APIs in parallel, surfacing live coding stats (repos, stars, followers, DSA problem breakdown).
- 5
Layered UX details: Framer Motion page transitions, an IntersectionObserver-based sticky TOC with active-heading tracking, a scroll-driven reading progress bar, a print-friendly resume view, and a hamburger menu on mobile.
- 6
Built the contact form on Resend with client-side loading/success/error states — reply_to set so replies go straight to the sender.
Outcomes
- Fresh Notion content appears on the live site within 5 minutes via the revalidate webhook.
- Every page under 150 KB first-load JS. 25 routes pre-rendered at build.
- Zero third-party lock-in — swap Notion for MDX in a day if needed.
Learnings
ISR + on-demand revalidation is the sweet spot for content sites — you get static-fast delivery without a 'redeploy on every edit' loop. notion-to-md handles ~95% of Notion blocks perfectly; the last 5% you either accept or write a small custom renderer for. Fetching third-party stats server-side is more reliable than embedding their images (which routinely 503 on free-tier services).