A high-performance Next.js 16 blog written in TypeScript that uses Notion's Public API as a headless CMS. Features Turbopack builds, 75% test coverage, optimized images with WebP/AVIF support, and comprehensive SEO with JSON Feed and Schema.org structured data.
Live Site: https://brennanmoore.com
- β‘ Turbopack Builds: 1.7s production builds with Next.js 16's default Turbopack compiler
- π Static Generation: 38 pages pre-rendered at build time for instant loading
- πΌοΈ Image Optimization: WebP/AVIF support with responsive sizing (40-60% bandwidth reduction)
- π― Perfect Scores: Consistently scores 100 on Vercel's performance dashboard
- π Multi-Format Feeds:
- RSS 2.0 feed (
/rss.xml) for traditional feed readers - JSON Feed 1.1 (
/feed.json) with full content and word counts - Auto-discovery links in HTML for easy subscription
- RSS 2.0 feed (
- π Schema.org JSON-LD: Rich structured data with Person, Blog, BlogPosting, and Photograph types
- πΊοΈ Dynamic Sitemap: Auto-generated with priority and change frequency
- π± Social Metadata: OpenGraph and Twitter Card support
- β 75% Test Coverage: 221 comprehensive tests with Vitest and React Testing Library
- π― Type Safety: Strict TypeScript with full type coverage
- π Security: Content Security Policy (CSP) and secure headers
- π Well-Documented: Comprehensive docs in
/docsand inline comments - π¨ Code Quality: ESLint 9, Prettier, and automated formatting
- π Notion as CMS: Easy content management through Notion's intuitive interface
- πΎ Smart Caching: Local JSON caching for fast builds and offline development
- πΈ Dual Content Types: Separate sections for blog posts and photo galleries
- π·οΈ Series Support: VBC (Value-Based Care) series with navigation
| Category | Technology | Version | Purpose |
|---|---|---|---|
| Framework | Next.js | 16.0.0 | App Router with Turbopack |
| Language | TypeScript | 5.9.3 | Type-safe development |
| Styling | Tailwind CSS | 4.1.14 | Utility-first CSS (v4 with Lightning CSS) |
| CMS | Notion API | 5.3.0 | Content management |
| Testing | Vitest | 4.0.2 | Fast unit testing |
| Testing | React Testing Library | Latest | Component testing |
| Code Quality | ESLint | 9.38.0 | Code linting |
| Deployment | Vercel | N/A | Edge deployment |
Runtime: Node.js 22.x (minimum 20.9.0 for Next.js 16)
homepage-notion-nextjs/
βββ src/
β βββ app/ # Next.js 16 App Router
β β βββ writing/[slug]/ # Blog post pages
β β βββ photos/[slug]/ # Photo gallery pages
β β βββ feed.json/ # JSON Feed 1.1 route
β β βββ rss.xml/ # RSS 2.0 feed route
β β βββ sitemap.xml/ # Dynamic sitemap
β β βββ robots.txt/ # Robots.txt route
β βββ components/ # React components
β β βββ post-card.tsx # Blog post card
β β βββ photo-card.tsx # Photo gallery card
β β βββ post-layout.tsx # Shared post layout
β β βββ mdx-component.tsx # MDX content renderer
β βββ lib/ # Utilities & integrations
β β βββ notion.ts # Notion API client (v5.x)
β β βββ config.ts # Environment config
β β βββ errors.ts # Error handling utilities
β β βββ page-utils.ts # SEO and metadata helpers
β βββ hooks/ # Custom React hooks
βββ __tests__/ # Vitest tests (221 tests)
β βββ app/ # Route tests
β βββ components/ # Component tests
β βββ lib/ # Utility tests
βββ scripts/
β βββ cache-posts.ts # Notion content caching
βββ docs/ # Project documentation
βββ posts-cache.json # Cached blog posts
βββ photos-cache.json # Cached photos
βββ public/images/ # Optimized images
βββ CLAUDE.md # AI context & patterns
βββ README.md # This file
Follow the Notion API Getting Started Guide to create an integration and obtain:
NOTION_TOKEN: Your Notion integration token (starts withsecret_)NOTION_POSTS_DATABASE_ID: Database ID for blog posts (data source ID)NOTION_PHOTOS_DATABASE_ID: Database ID for photo gallery (data source ID)SITE_URL: Your site URL for absolute links (e.g.,https://brennanmoore.com)
Important: Use Notion data source IDs (v5.x API), not database IDs.
Create a .env.local file in the project root:
NOTION_TOKEN=secret_your-notion-integration-token
NOTION_POSTS_DATABASE_ID=abc123def456
NOTION_PHOTOS_DATABASE_ID=xyz789abc123
SITE_URL=https://brennanmoore.comnpm installSystem Requirements: Node.js 20.9.0 or higher
Before running the dev server, cache your Notion content:
npm run cache:postsThis creates posts-cache.json and photos-cache.json for faster builds.
npm run devOpen http://localhost:3000 to view your blog.
Dev Features:
- β‘ Turbopack for instant HMR (Hot Module Replacement)
- π Fast refresh on file changes
- π οΈ TypeScript type checking in real-time
npm run build # Build with Turbopack (1.7s)
npm start # Start production serverBuild Output: 38 static pages generated at build time for optimal performance.
This project is optimized for deployment on Vercel:
- Push your code to a Git repository.
- Deploy using the Vercel CLI or Vercel Dashboard.
- Ensure environment variables are set in the Vercel dashboard under "Settings > Environment Variables".
The project has 75.79% test coverage with 221 comprehensive tests using Vitest and React Testing Library.
npm test # Run all tests
npm run test:watch # Watch mode for development
npm run test:ui # Open Vitest UI
npm run test:coverage # Generate coverage report| Category | Coverage | Tests |
|---|---|---|
| Components | High | 66 tests (PostCard, PhotoCard, VBCFooter, etc.) |
| Utilities | High | 48 tests (config, errors, page-utils) |
| API Routes | Complete | 42 tests (RSS, JSON Feed, sitemap) |
| Hooks | Complete | 7 tests (use-mobile) |
| Integration | Good | 58 tests (pages, layouts) |
Key Test Features:
- Type-safe mocking with
vi.mocked() - Timezone-safe date assertions
- Behavioral testing (not implementation details)
- Snapshot testing for UI consistency
See CLAUDE.md for testing patterns and conventions.
- Colors & Typography: Edit
tailwind.config.tsfor theme customization - Layout: Modify components in
src/components/for structural changes - Images: Configure quality and formats in
next.config.tsunderimages
- Notion Databases: Update your Notion pages to add posts or photos
- Sections: Modify
src/lib/notion.tsto add new content sections - Metadata: Edit
src/lib/page-utils.tsfor SEO and Schema.org customization
- Sitemap: Configure priorities in
src/app/sitemap.xml/route.ts - RSS Feed: Customize feed details in
src/app/rss.xml/route.ts - JSON Feed: Modify
src/app/feed.json/route.tsfor feed customization
- Image Quality: Adjust
qualitiesarray innext.config.ts(default:[75, 85]) - Cache TTL: Modify
minimumCacheTTLinnext.config.ts(default: 30 days) - Caching Strategy: Update
scripts/cache-posts.tsfor different caching behavior
Comprehensive documentation is available in the /docs directory:
- CLAUDE.md: AI context, patterns, and conventions (start here!)
- Code Quality Audit: Test coverage and quality metrics
- Next.js 16 Upgrade: Breaking changes and migration guide
- Image Optimization: Performance optimization strategies
- Dependency Updates: Package update strategy
Image Quality Warnings
Image with src "..." is using quality "85" which is not configured
Solution: Add qualities: [75, 85] to images config in next.config.ts
Notion API Errors
- Ensure using Notion API v5.x with
dataSources.query()notdatabases.query() - Verify
data_source_id(notdatabase_id) in environment variables - Check integration has access to your Notion pages
Build Failures
- Run
npm run cache:postsbefore building - Ensure Node.js version is 20.9.0 or higher
- Clear
.nextcache:rm -rf .next && npm run build
See CLAUDE.md for more troubleshooting tips.
This project is licensed under the MIT License.
- Built with Next.js 16 by Vercel
- Based on Notion Blog by thegesturs
- Powered by Notion's Public API
- Testing with Vitest and React Testing Library
Made with β€οΈ using Next.js and Notion