karan.dev
All projects
Full-Stack

Personal Portfolio & Developer Blog

April 2026

The site you're on — Next.js 15 App Router portfolio with a Notion-backed blog, live GitHub/GFG stats, and on-demand ISR revalidation.

Next.js 15TypeScriptTailwind CSSNotion APIFramer MotionResendVercel

Next 15

App Router + ISR

Notion

headless CMS

Live

GitHub + GFG APIs

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. 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. 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. 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. 4

    Server-side fetched GitHub + GeeksforGeeks APIs in parallel, surfacing live coding stats (repos, stars, followers, DSA problem breakdown).

  5. 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. 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).