Note: This documentation uses Next.js App Router. If you're still on Pages Router, see the migration guide.
📚 boiler.plate - Modules Reference
This document provides developer-level details about each module, including files generated, dependencies, environment variables, and integration behavior.
Use this as your reference when composing projects with boiler.plate.
📋 Auth - At a Glance
⏱️ Time to Green
5-10 minutes
🔧 ENV Variables
- DATABASE_URL
- NEXTAUTH_SECRET
- NEXTAUTH_URL
- JWT_SECRET
📄 Pages Delivered
- /login
- /signup
- /api/auth/[...nextauth]/route.ts
⚠️ Gotchas
- Requires database module
- JWT_SECRET must be 32+ chars
🔐 Auth Module
Purpose: Provide authentication & authorization (signup, login, logout, basic roles).
Features
- NextAuth.js v5 integration or simple email/password system (bcrypt + sessions)
- Prisma
User
model generation - Login/signup pages (
/login
,/signup
), optional password reset - Middleware to protect routes
<AuthProvider>
React context (NextAuth CSR) or hooks (useSession
)
Files Generated
- app/(auth)/login/page.tsx
- app/(auth)/signup/page.tsx
- app/api/auth/[...nextauth]/route.ts (if NextAuth)
- prisma/schema.prisma → adds User model
- middleware.ts → protects routes
Dependencies
{ "dependencies": { "next-auth": "^5", "@auth/prisma-adapter": "^2", "@prisma/client": "^5", "bcrypt": "^5", "zod": "^3" } }
Environment Variables
DATABASE_URL="your-database-url" NEXTAUTH_SECRET="your-secret-key" NEXTAUTH_URL="http://localhost:3000" JWT_SECRET="your-jwt-secret"
📋 Stripe - At a Glance
⏱️ Time to Green
10-15 minutes
🔧 ENV Variables
- STRIPE_SECRET_KEY
- NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
- NEXT_PUBLIC_SITE_URL
- NEXT_PUBLIC_STRIPE_PRICE_ID
📄 Pages Delivered
- /pricing
- /billing
- /api/stripe/webhook/route.ts
- /api/stripe/checkout/route.ts
⚠️ Gotchas
- Use price_ not prod_ IDs
- Must be recurring for subscriptions
- Configure portal settings
💳 Stripe Modules
1. Stripe Core
Provides Stripe integration primitives.
Features
- Webhook handler (
/api/stripe/webhook
) - Server-side client (
lib/stripe.ts
) - Typed utils & events
StripeProvider
React contextStripeButton
component
Files Generated
- app/api/stripe/webhook/route.ts
- lib/stripe.ts
- components/StripeButton.tsx
Dependencies
{ "dependencies": { "stripe": "^14", "@stripe/stripe-js": "^4" } }
Env Vars
STRIPE_SECRET_KEY="sk_test_..." NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_test_..." NEXT_PUBLIC_SITE_URL="http://localhost:3000"
2. Stripe Subscriptions
Builds on Core, adds full SaaS billing.
Features
/pricing
page with checkout/billing
page with portal + status- API routes for checkout, portal, status
- Customer creation linked to Auth user
Files Generated
- app/pricing/page.tsx
- app/billing/page.tsx
- app/api/stripe/checkout/route.ts
- app/api/stripe/portal/route.ts
- app/api/stripe/status/route.ts
Env Vars
- NEXT_PUBLIC_STRIPE_PRICE_ID (must be recurring)
⚠️ Common Errors
- Using
prod_...
instead ofprice_...
→ must use Price ID - One-time price in subscription mode → must create recurring
- Portal error → save a config in Stripe Test Portal Settings
📋 Database - At a Glance
⏱️ Time to Green
2-5 minutes
🔧 ENV Variables
- DATABASE_URL
📄 Pages Delivered
- prisma/schema.prisma
- .env.example
⚠️ Gotchas
- Choose SQLite for dev, Postgres for prod
- Run prisma generate after setup
🗄️ Database Modules
db-sqlite
- Local SQLite database
- Auto Prisma schema
- Great for prototyping
db-postgres
- Production-ready Postgres
- Prisma schema + migrations
Files Generated
- prisma/schema.prisma
- .env.example with DATABASE_URL
Dependencies
{ "dependencies": { "prisma": "^5", "@prisma/client": "^5" } }
📋 Admin - At a Glance
⏱️ Time to Green
2-3 minutes
🔧 ENV Variables
📄 Pages Delivered
- lib/admin.ts
- middleware.ts
⚠️ Gotchas
- Requires auth module
- Next.js App Router middleware included
🛡️ Admin Module
Features
- Admin-only routes
- Next.js App Router middleware
- Utilities for checking admin role
Files Generated
- lib/admin.ts
- middleware.ts
Dependencies
{ "dependencies": { "uuid": "^9" } }
Middleware Example
// middleware.ts (at project root) import { NextResponse } from "next/server"; export function middleware(req: Request) { // Simple example: check admin header flag const url = new URL(req.url); if (url.pathname.startsWith("/admin") && !req.headers.get("x-admin")) { return new NextResponse("Forbidden", { status: 403 }); } return NextResponse.next(); } export const config = { matcher: ["/admin/:path*"], };
Why not Express?
Next.js App Router provides built-in middleware capabilities that cover most use cases without requiring Express. The middleware runs at the edge, is more performant, and integrates seamlessly with Next.js routing and API routes.
📋 Analytics - At a Glance
⏱️ Time to Green
3-5 minutes
🔧 ENV Variables
- NEXT_PUBLIC_ANALYTICS_PROVIDER
- NEXT_PUBLIC_POSTHOG_KEY
- NEXT_PUBLIC_PLAUSIBLE_DOMAIN
📄 Pages Delivered
- /analytics-demo (optional)
- lib/analytics/
⚠️ Gotchas
- Respects doNotTrack
- Zero external dependencies
- Auto page view tracking
📊 Analytics Module
Features
- Multi-Provider Support - PostHog and Plausible drivers included
- TypeScript - Full type safety with Zod validation
- Privacy-First - Respects
navigator.doNotTrack
preference - Auto Page Views - Automatic page view tracking with debouncing
- No-Op Mode - Safe fallback when analytics is disabled
- React Hooks - Easy-to-use
useAnalytics()
hook - Extensible - Easy to add new analytics providers
- Zero Dependencies - No interference with other modules
Files Generated
- app/lib/analytics/config.ts
- app/lib/analytics/analytics-client.ts
- app/lib/analytics/provider.tsx
- app/lib/analytics/use-analytics.ts
- app/lib/analytics/events.ts
- app/lib/analytics/index.ts
- app/(examples)/analytics-demo/page.tsx (optional)
Dependencies
{ "dependencies": { "zod": "^3" }, "optional": { "posthog-js": "^1" // if using PostHog } }
Environment Variables
NEXT_PUBLIC_ANALYTICS_PROVIDER="posthog" NEXT_PUBLIC_POSTHOG_KEY="phc_..." NEXT_PUBLIC_POSTHOG_HOST="https://app.posthog.com" NEXT_PUBLIC_PLAUSIBLE_DOMAIN="yourdomain.com" NEXT_PUBLIC_PLAUSIBLE_API_HOST="https://plausible.io"
Module Flags
addDemoPage
(boolean, default: false) - Adds demo page at /analytics-demoautoPageview
(boolean, default: true) - Automatic page view tracking
💡 Usage Example
import { useAnalytics } from "@/app/lib/analytics"; function MyComponent() { const { track, identify } = useAnalytics(); const handleClick = () => { track("button_clicked", { buttonId: "cta" }); }; return <button onClick={handleClick}>Click me!</button>; }
📋 S3 Storage - At a Glance
⏱️ Time to Green
8-12 minutes
🔧 ENV Variables
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- AWS_REGION
- S3_BUCKET
📄 Pages Delivered
- /storage-demo (optional)
- api/storage/s3/
- lib/storage/s3/
⚠️ Gotchas
- Private bucket required
- Configure CORS on S3
- TTL-limited URLs
☁️ S3 Storage Module
Features
- Presigned Uploads - Direct file uploads to S3 with presigned URLs
- Multipart Support - Optional multipart upload for large files
- Download URLs - Secure presigned download URLs
- Prefix Strategies - Flexible S3 key organization (user/org/flat)
- TypeScript - Full type safety with Zod validation
- Security - Private bucket, TTL-limited URLs, MIME validation
- React Hooks - Easy-to-use
useUpload()
anduseMultipartUpload()
hooks - Extensible - Stub functions for authentication integration
Files Generated
- app/api/storage/s3/presign/route.ts
- app/api/storage/s3/sign-download/route.ts
- app/api/storage/s3/presign-multipart/route.ts (if enabled)
- app/api/storage/s3/complete-multipart/route.ts (if enabled)
- app/lib/storage/s3/config.ts
- app/lib/storage/s3/client.ts
- app/lib/storage/s3/server.ts
- app/lib/storage/s3/upload.ts
- app/(examples)/storage-demo/page.tsx (optional)
Dependencies
{ "dependencies": { "@aws-sdk/client-s3": "^3", "@aws-sdk/s3-request-presigner": "^3", "zod": "^3" } }
Environment Variables
AWS_ACCESS_KEY_ID="AKIA..." AWS_SECRET_ACCESS_KEY="..." AWS_REGION="us-east-1" S3_BUCKET="your-bucket-name" S3_PREFIX="users" MAX_UPLOAD_MB="20" S3_DOWNLOAD_TTL="60"
Module Flags
multipart
(boolean, default: false) - Enables multipart upload supportaddDemoPage
(boolean, default: false) - Adds demo page at /storage-demoprefixStrategy
(user | org | flat, default: user) - Controls S3 key organization
💡 Usage Example
import { useUpload } from "@/app/lib/storage/s3/upload"; function MyComponent() { const { upload, isUploading } = useUpload(); const handleFileUpload = async (file: File) => { const result = await upload(file); console.log("Upload successful:", result.key); }; return ( <input type="file" onChange={(e) => { const file = e.target.files?.[0]; if (file) handleFileUpload(file); }} disabled={isUploading} /> ); }
📋 User Settings - At a Glance
⏱️ Time to Green
5-8 minutes
🔧 ENV Variables
- NEXT_PUBLIC_DEFAULT_TIMEZONE
- NEXT_PUBLIC_SUPPORTED_LOCALES
📄 Pages Delivered
- /settings
- /settings/profile
- /settings/security
- /settings/preferences
⚠️ Gotchas
- Requires auth module
- Adaptable architecture
- Optional billing integration
⚙️ User Settings Module
Features
- Profile Management - Update name, handle, timezone, and avatar
- Security Settings - Password change (when supported by auth provider)
- Preferences - Language, email notifications, and display settings
- Avatar Upload - Support for S3 storage with Gravatar/monogram fallback
- Billing Integration - Optional Stripe portal integration
- Adaptable Architecture - Works with any authentication provider via adapters
Files Generated
- app/settings/layout.tsx
- app/settings/page.tsx
- app/settings/profile/page.tsx
- app/settings/security/page.tsx
- app/settings/preferences/page.tsx
- app/settings/billing/page.tsx (if includeBilling enabled)
- app/api/settings/profile/update/route.ts
- app/api/settings/security/change-password/route.ts
- app/api/settings/preferences/update/route.ts
- app/api/settings/billing/portal/route.ts (if includeBilling enabled)
- app/lib/user-settings/adapters/auth.ts
- app/lib/user-settings/adapters/avatar.ts
- app/lib/user-settings/adapters/billing.ts
- app/lib/user-settings/validation.ts
- app/lib/user-settings/components/section.tsx
- app/lib/user-settings/components/form.tsx
- app/lib/user-settings/components/avatar-uploader.tsx
Dependencies
{ "dependencies": { "zod": "^3", "react-hook-form": "^7", "@hookform/resolvers": "^3" }, "optional": { "@supabase/supabase-js": "^2", // if using Supabase "next-auth": "^5", // if using NextAuth "@stripe/stripe-js": "^4" // if using Stripe billing } }
Environment Variables
NEXT_PUBLIC_DEFAULT_TIMEZONE="UTC" NEXT_PUBLIC_SUPPORTED_LOCALES="en,fr"
Module Flags
includeBilling
(boolean, default: false) - Include billing page and portal functionalityincludeAvatarUpload
(boolean, default: true) - Enable avatar upload with storage adapter supportaddDemoData
(boolean, default: false) - Pre-fill forms with demo data (development only)
Adapters
- UserAuthAdapter (Required) - Handles authentication and profile updates
- AvatarStorageAdapter (Optional) - Handles avatar upload (auto-detects S3)
- BillingAdapter (Optional) - Handles billing portal (auto-detects Stripe)
💡 Usage Example
// lib/user-settings/adapters/auth.ts import { SupabaseAuthAdapter } from './supabase-adapter'; export const authAdapter = new SupabaseAuthAdapter(); // Automatically integrates with S3 storage and Stripe billing if available // No additional configuration needed for adapters
📋 Emails - At a Glance
⏱️ Time to Green
3-5 minutes
🔧 ENV Variables
- EMAIL_PROVIDER
- EMAIL_FROM
- RESEND_API_KEY
- POSTMARK_TOKEN
📄 Pages Delivered
- /emails/preview (optional)
- api/email/send (optional)
- emails/templates/
⚠️ Gotchas
- Provider abstraction
- React Email templates
- Preview system included
📧 Emails Transactional Module
Features
- Provider Abstraction - Switch between Resend, Postmark, or no-op drivers
- React Email Templates - Type-safe email templates with React components
- Multiple Templates - Welcome, Invite, and Receipt email templates included
- Preview System - Optional email preview page for development
- Test API - Optional API route for testing email sending
- TypeScript - Full type safety with Zod validation
- Security - Production-safe with proper authentication and rate limiting
- Idempotent - Safe to run multiple times without duplication
Files Generated
- app/lib/email/config.ts
- app/lib/email/provider.ts
- app/lib/email/send.ts
- app/emails/components/Layout.tsx
- app/emails/components/Button.tsx
- app/emails/templates/Welcome.tsx
- app/emails/templates/Invite.tsx
- app/emails/templates/Receipt.tsx
- app/emails/preview/page.tsx (if addPreview enabled)
- app/api/email/send/route.ts (if addSendRoute enabled)
Dependencies
{ "dependencies": { "resend": "^3", "@react-email/components": "^0.0", "zod": "^3" }, "optional": { "postmark": "^4" // if addPostmark=true } }
Environment Variables
EMAIL_PROVIDER="resend" EMAIL_FROM="boiler.plate <support@example.dev>" RESEND_API_KEY="re_..." POSTMARK_TOKEN="..." POSTMARK_MESSAGE_STREAM="outbound" EMAIL_TEST_TOKEN="optional"
Module Flags
provider
(resend | postmark | none, default: resend) - Default email provideraddPreview
(boolean, default: false) - Add email preview pageaddSendRoute
(boolean, default: false) - Add test email API routeaddPostmark
(boolean, default: false) - Install postmark dependency
Providers
- Resend (Default) - Modern email API with great deliverability
- Postmark (Optional) - Transactional email specialist
- None - No-op mode for development/testing
💡 Usage Example
import { sendEmail } from '@/app/lib/email/send'; import WelcomeEmail from '@/app/emails/templates/Welcome'; // Send React template email await sendEmail({ to: 'user@example.com', subject: 'Welcome to boiler.plate!', react: <WelcomeEmail firstName="John" /> }); // Send HTML email await sendEmail({ to: 'user@example.com', subject: 'Test Email', html: '<h1>Hello World!</h1>' });
📋 Feature Flags - At a Glance
⏱️ Time to Green
2-3 minutes
🔧 ENV Variables
- NEXT_PUBLIC_FLAGS_PROVIDER
- NEXT_PUBLIC_FLAGS_HTTP_URL
- NEXT_PUBLIC_FLAGS_SEED
📄 Pages Delivered
- /flags-demo (optional)
- config/flags.json
- lib/flags/
⚠️ Gotchas
- Local provider by default
- User-based rollouts
- Hot reload support
🚩 Feature Flags Module
Features
- Local Provider - Read flags from a versioned JSON file
- HTTP Provider - Poll remote endpoints for dynamic flag updates
- User-based Rollouts - Consistent user bucketing with configurable seed
- TypeScript Support - Full type safety with Zod validation
- React Hooks - Easy-to-use hooks for client-side flag access
- Server-side Helpers - Server-side flag resolution without hooks
- Hot Reload - Automatic updates when flags change (local provider)
- Error Handling - Graceful fallbacks and error recovery
- Extensible - Easy to add new providers (Unleash, Flagsmith, etc.)
Files Generated
- app/lib/flags/types.ts
- app/lib/flags/config.ts
- app/lib/flags/hash.ts
- app/lib/flags/provider.ts
- app/lib/flags/local.ts
- app/lib/flags/http.ts
- app/lib/flags/use-flags.ts
- app/config/flags.json
- app/(examples)/flags-demo/page.tsx (if addDemoPage enabled)
Dependencies
{ "dependencies": { "zod": "^3" } }
Environment Variables
NEXT_PUBLIC_FLAGS_PROVIDER="local" NEXT_PUBLIC_FLAGS_HTTP_URL="https://api.example.com/flags" NEXT_PUBLIC_FLAGS_POLL_MS="15000" NEXT_PUBLIC_FLAGS_SEED="bp"
Module Flags
addDemoPage
(boolean, default: false) - Add demo page at /flags-demo
Providers
- Local (Default) - JSON file-based flags with hot reload
- HTTP (Optional) - Remote endpoint polling for dynamic updates
💡 Usage Example
import { useFeatureFlag, useRemoteConfig, FlagsProvider } from '@/app/lib/flags/use-flags'; // Client-side usage function MyComponent() { const enabled = useFeatureFlag('newCheckout', { userId: 'user-123' }); const maxProjects = useRemoteConfig<number>('limits.maxProjects', 3); return ( <div> {enabled && <NewCheckoutButton />} <p>Max projects: {maxProjects}</p> </div> ); } // Server-side usage import { getFlag, getConfig } from '@/app/lib/flags/provider'; const isEnabled = await getFlag('newCheckout', 'user-123');
📋 Notifications - At a Glance
⏱️ Time to Green
2-3 minutes
🔧 ENV Variables
- NEXT_PUBLIC_NOTIF_POLL_INTERVAL_MS
📄 Pages Delivered
- components/navbar-bell.tsx
- lib/notifications/
- api/notifications/
⚠️ Gotchas
- Zero external dependencies
- Flexible storage
- Real-time ready
🔔 In-App Notifications Module
Features
- Toast Notifications - Beautiful, accessible toast notifications with multiple variants
- Notification Center - Optional persistent notification center with read/unread states
- Flexible Storage - In-memory storage by default, with Prisma support
- Real-time Ready - Extensible architecture for WebSocket/Pusher integration
- Zero Dependencies - Uses only React and web APIs (no external UI libraries required)
Files Generated
- app/lib/notifications/toast/provider.tsx
- app/lib/notifications/toast/use-toast.ts
- app/lib/notifications/toast/toast.tsx
- app/lib/notifications/center/client.ts
- app/lib/notifications/center/use-notifications.ts
- app/lib/notifications/center/store-adapter.ts
- app/lib/notifications/center/notifier-adapter.ts
- app/api/notifications/list/route.ts (if withNotificationCenter enabled)
- app/api/notifications/create/route.ts (if withNotificationCenter enabled)
- app/api/notifications/mark-read/route.ts (if withNotificationCenter enabled)
- app/api/notifications/mark-all-read/route.ts (if withNotificationCenter enabled)
- app/api/notifications/delete/route.ts (if withNotificationCenter enabled)
- components/navbar-bell.tsx (if withNavbarBell enabled)
Dependencies
{ "dependencies": { // Zero external dependencies - uses only React and web APIs }, "optional": { "@prisma/client": "^5" // if using Prisma for persistent storage } }
Environment Variables
NEXT_PUBLIC_NOTIF_POLL_INTERVAL_MS="20000"
Module Flags
withNotificationCenter
(boolean, default: false) - Enable persistent notification centerwithNavbarBell
(boolean, default: true) - Add bell icon to navbarrealtime
(boolean, default: false) - Enable real-time notifications
Storage Options
- Memory Store (Default) - In-memory storage, lost on server restart
- Prisma Store (Optional) - Persistent database storage with Prisma
💡 Usage Example
import { useToast } from "@/app/lib/notifications/toast/use-toast"; import { useNotifications } from "@/app/lib/notifications/center/use-notifications"; // Toast notifications function MyComponent() { const { success, error } = useToast(); const handleSubmit = async () => { try { await saveData(); success("Data saved successfully!"); } catch (err) { error("Failed to save data"); } }; return <button onClick={handleSubmit}>Save Data</button>; } // Notification center function NotificationCenter() { const { notifications, unreadCount, markAsRead } = useNotifications(); return ( <div> <h3>Notifications ({unreadCount})</h3> {notifications.map(notification => ( <div key={notification.id} onClick={() => markAsRead(notification.id)}> {notification.title} </div> ))} </div> ); }
🔗 Multi-Module Integration
- Dependencies auto-resolved (e.g. Auth → DB required)
- Conflicts detected (e.g. cannot use both
db-sqlite
anddb-postgres
)
Cross integration examples:
- Auth + Stripe → store
stripeCustomerId
on user model
🚨 Troubleshooting
Stripe
- 400 errors on checkout → wrong Price ID type
- Portal returns no URL → missing configuration in Stripe Dashboard
Supabase
- Missing keys → ensure
.env
matches Supabase dashboard
General
❌ Circular dependency detected: teams → admin → teams
→ fixmodule.json
- Hook failed → check script syntax