/** @type {import('next').NextConfig} */ // ============================================ // Next.js 16 Configuration // ============================================ // This configuration is optimized for Next.js 16 // Deprecated options have been removed (swcMinify, reactStrictMode) // SWC minification is now default in Next.js 16 // Production-ready Next.js configuration with standalone output // This configuration is optimized for Docker deployment with minimal image size // // Key features: // - Standalone output mode (includes only necessary dependencies) // - Image optimization with modern formats // - Static Site Generation (SSG) for all blog posts // - Production-grade caching and performance settings // // Usage: // 1. Copy this file to project root: cp next.config.js.production next.config.js // 2. Build application: npm run build // 3. The .next/standalone directory will contain everything needed to run the app const nextConfig = { // ============================================ // Standalone Output Mode // ============================================ // This is REQUIRED for Docker deployment // Outputs a minimal server with only necessary dependencies // Reduces Docker image size from ~1GB to ~150MB output: 'standalone', // ============================================ // Image Optimization // ============================================ images: { // Modern image formats (smaller file sizes) formats: ['image/avif', 'image/webp'], // Device sizes for responsive images // Next.js will generate optimized images for these widths deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], // Image sizes for component size prop imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], // Cache optimized images for 30 days minimumCacheTTL: 60 * 60 * 24 * 30, // Allow SVG rendering (with security measures) dangerouslyAllowSVG: true, contentDispositionType: 'attachment', contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;", // Disable image optimization during build (optional) // Uncomment if build times are too long // unoptimized: false, // External image domains (if loading images from CDN) // Uncomment and add domains if needed // remotePatterns: [ // { // protocol: 'https', // hostname: 'cdn.example.com', // }, // ], }, // ============================================ // Performance Optimization // ============================================ // Compress static pages (reduces bandwidth) compress: true, // ============================================ // Production Settings // ============================================ // Disable X-Powered-By header for security poweredByHeader: false, // Generate ETags for caching generateEtags: true, // ============================================ // Static Generation Settings // ============================================ // Automatically generate static pages at build time // This is the default behavior for Next.js App Router // All markdown blog posts will be pre-rendered // ============================================ // TypeScript Settings // ============================================ // Type checking during build // Set to false to skip type checking (not recommended) typescript: { // ignoreBuildErrors: false, }, // ============================================ // ESLint Settings // ============================================ // ESLint during build // Set to false to skip linting (not recommended) // ============================================ // Experimental Features (Next.js 16) // ============================================ experimental: { // Enable optimistic client cache // Improves navigation performance staleTimes: { dynamic: 30, static: 180, }, // Optimize package imports for smaller bundles optimizePackageImports: [ 'react-markdown', 'rehype-raw', 'rehype-sanitize', 'remark-gfm', ], // Enable PPR (Partial Prerendering) - Next.js 16 feature // Uncomment to enable (currently in beta) // ppr: false, }, // ============================================ // Security Headers (PRODUCTION READY) // ============================================ // Comprehensive security headers for public deployment // Note: Caddy reverse proxy may also set these as backup async headers() { return [ { source: '/:path*', headers: [ // Prevent MIME type sniffing { key: 'X-Content-Type-Options', value: 'nosniff', }, // Prevent clickjacking { key: 'X-Frame-Options', value: 'DENY', }, // XSS Protection (legacy browsers) { key: 'X-XSS-Protection', value: '1; mode=block', }, // HSTS - Force HTTPS for 1 year { key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains; preload', }, // Referrer Policy - Protect user privacy { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin', }, // Permissions Policy - Disable unnecessary browser features { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=(), interest-cohort=()', }, // Content Security Policy - Restrict resource loading // Note: Next.js requires 'unsafe-inline' for styled-jsx { key: 'Content-Security-Policy', value: [ "default-src 'self'", "script-src 'self' 'unsafe-inline' 'unsafe-eval'", "style-src 'self' 'unsafe-inline'", "img-src 'self' data: https:", "font-src 'self' data:", "connect-src 'self'", "frame-ancestors 'none'", "base-uri 'self'", "form-action 'self'", ].join('; '), }, ], }, // Aggressive caching for static assets { source: '/_next/static/:path*', headers: [ { key: 'Cache-Control', value: 'public, max-age=31536000, immutable', }, ], }, { source: '/images/:path*', headers: [ { key: 'Cache-Control', value: 'public, max-age=31536000, immutable', }, ], }, ] }, // ============================================ // Redirects (Optional) // ============================================ // Add permanent redirects for old URLs // Uncomment and add your redirects // // async redirects() { // return [ // { // source: '/old-blog/:slug', // destination: '/blog/:slug', // permanent: true, // }, // ] // }, // ============================================ // Rewrites (Optional) // ============================================ // Add URL rewrites for API proxying or URL masking // Uncomment and add your rewrites // // async rewrites() { // return [ // { // source: '/api/:path*', // destination: 'https://api.example.com/:path*', // }, // ] // }, } module.exports = nextConfig