Next.js 15+ π€ Tailwind CSS v4 π€ pnpm π€ Notion as CMS π€ Custom Notion Renderer π€ Pagefind Search π€ Vercel + GitHub Actions.
π You can read this post to understand the ideas behind and create your own a site like mine.
π What's new in v7? Check this post.
π§‘ If what I do is helpful to you for some reason, please consider supporting me. Thank you!
π Version 1 (Jekyll): v1.dinhanhthi.com -- source.
π Version 2 (Jekyll): v2.dinhanhthi.com -- source.
π Version 3 (Jekyll): v3.dinhanhthi.com -- source.
π Version 4 (Gatsby, canceled at 60%): demo of what I did -- source.
π Version 5 (11ty): v5.dinhanhthi.com -- source.
π Version 6 (use separated notion-x repo): source.
- CMS: Notion β all content lives in Notion databases
- Build: All pages pre-rendered at build time via
generateStaticParams(full SSG) - Search: Pagefind β client-side search, indexes HTML at build time
- Deploy: Vercel β deployed via GitHub Actions (not Vercel's auto-build)
- Schedule: GitHub Actions cron builds every 3 days to pull latest Notion content
- OG Images:
/api/ogEdge Function on Vercel (free, no server needed)
You have to install globally Nodejs >=22 (recommend using nvm) and pnpm first. Then
# Copy and fill all variables (1st time only)
cp example.env.local .env.local
# install (1st time only)
pnpm install
# Turn off being collected data via Telemetry program
# https://nextjs.org/telemetry
pnpm next telemetry disable
# dev
pnpm run dev # port 3004
# build (includes Pagefind indexing via postbuild)
pnpm run build
# serve (need to build first)
pnpm start # port 3004
# reinstall all
pnpm run reinstall
# clean
pnpm run clean
# prettier
pnpm run prettier
# clear pnpm cache (helpful sometimes)
pnpm store prune- GitHub Actions builds the site on a schedule (every 3 days) or on push to
main/dev - During build, Next.js calls Notion API to fetch all content and pre-render every page
- Pagefind indexes the generated HTML to create a client-side search index
- The pre-built output is deployed to Vercel via
vercel deploy --prebuilt - If build fails, GitHub sends email notification and Vercel keeps the previous deployment
- Create Vercel project: Go to vercel.com, import repo, link to your GitHub repo
- Disable auto-build: In Vercel project settings > Git, disable "Auto Deploy" (builds happen via GitHub Actions, not Vercel)
- Get Vercel credentials: Run
vercel linklocally to create.vercel/project.json, then noteorgIdandprojectId - Create Vercel token: Go to vercel.com/account/tokens and create a token
- Add Notion env vars to Vercel: In Vercel project > Settings > Environment Variables, add ALL variables from
example.env.local(Notion tokens, database IDs, property keys, etc.)- For Production environment: set
ENV_MODE=prodandNEXT_PUBLIC_ENV_MODE=prod - For Preview environment: set
ENV_MODE=devandNEXT_PUBLIC_ENV_MODE=dev
- For Production environment: set
- Add GitHub secrets: In repo Settings > Secrets and variables > Actions, add:
VERCEL_TOKENβ from step 4VERCEL_ORG_IDβ from.vercel/project.jsonVERCEL_PROJECT_IDβ from.vercel/project.json
- Push to main β GitHub Actions will build and deploy automatically
mainbranch β production deployment (ENV_MODE=prod, only published posts)devbranch β preview deployment (ENV_MODE=dev, all posts including drafts)
Trigger a manual build from GitHub Actions > "Build and Deploy to Vercel" > "Run workflow".
# Set ENV_MODE in .env.local, then:
pnpm run build
# Check build output β you should see all pages being generated
# Pagefind index will be created in public/pagefind/