Packaging Configurations



1. optimizePackageImports

The optimizePackageImports feature helps improve performance by loading only the modules you actually use from large packages, while still allowing convenient import syntax with many named exports.

module.exports = { experimental: { optimizePackageImports: [ 'lodash', 'react-icons', '@mui/material', 'date-fns' ], }, }

Without optimization, importing from large packages can be expensive:

// This might bundle the entire lodash library import { debounce, throttle } from 'lodash' // With optimization, only debounce and throttle are bundled import { debounce, throttle } from 'lodash'

The following libraries are optimized by default:

This optimization is particularly valuable for:



2. output

The output configuration controls how Next.js builds and packages your application. The most important option is standalone, which creates a self-contained deployment package.

module.exports = { output: 'standalone', }

This creates a .next/standalone folder containing:

Manual deployment steps after build:

# Copy static assets cp -r public .next/standalone/ cp -r .next/static .next/standalone/.next/ # Start the server cd .next/standalone PORT=8080 HOSTNAME=0.0.0.0 node server.js

Advanced configuration for monorepos:

const path = require('path') module.exports = { output: 'standalone', outputFileTracingRoot: path.join(__dirname, '../../'), outputFileTracingExcludes: { '/api/heavy-endpoint': ['./large-unused-deps/**/*'], }, outputFileTracingIncludes: { '/api/special': ['./required-native-deps/**/*'], }, } (understand minimatch format here   299393 K  )

Benefits of standalone output:

Next.js uses @vercel/nft   1449   during next build to analyze and trace all files a page might need, including imports, require, and fs usage. The production server's dependencies are recorded in .next/next-server.js.nft.json. You can use these .nft.json files to identify and copy the required files for deployment.



3. serverExternalPackages

The serverExternalPackages option allows you to exclude specific dependencies from Next.js's automatic bundling for Server Components and Route Handlers, forcing them to use native Node.js require instead.

/** @type {import('next').NextConfig} */ const nextConfig = { serverExternalPackages: [ '@acme/native-module', 'sharp', 'canvas', 'sqlite3' ], } module.exports = nextConfig

This is necessary when packages:

Common packages that benefit from external bundling:

At the time of writing, these packages are automatically opted out of full Turbopack compatibility while maintainers work on fixes.



4. transpilePackages

The transpilePackages option allows Next.js to automatically transpile and bundle dependencies from local packages (monorepos) or external dependencies that need compilation.

/** @type {import('next').NextConfig} */ const nextConfig = { transpilePackages: [ '@my-company/shared-components', '@my-company/utils', 'some-es6-only-package' ], } module.exports = nextConfig

This replaces the need for next-transpile-modules and is useful for:

// Monorepo structure my-monorepo/ ├── apps/ │ └── web/ // Next.js app ├── packages/ │ ├── ui/ // Shared UI components │ ├── utils/ // Shared utilities │ └── config/ // Shared configuration // Configuration for the web app module.exports = { transpilePackages: ['@my-company/ui', '@my-company/utils'], }

Common use cases:

Example with a shared UI library:

// packages/ui/package.json { "name": "@my-company/ui", "main": "src/index.ts", // Points to source, not dist "exports": { ".": "./src/index.ts" } } // apps/web/next.config.js module.exports = { transpilePackages: ['@my-company/ui'], }

5. turbotrace

Tracing dependencies can be slow because it requires very complex computations and analysis. Next.js created turbotrace in Rust as a faster and smarter alternative to the JavaScript implementation for dependency tracing.

Dependency tracing is crucial for Next.js to understand which files and modules your application depends on, especially during the build process and for features like static optimization. The traditional JavaScript-based tracing can become a performance bottleneck in large applications with complex dependency graphs.

To enable turbotrace, you can add the following experimental configuration to your next.config.js:

module.exports = { experimental: { turbotrace: { logLevel: 'warning', logDetail: false, logAll: false, contextDirectory: process.cwd(), processCwd: process.cwd(), memoryLimit: 6000 }, }, }

logLevel - Controls the verbosity of turbotrace logging output. Default is 'error'.

turbotrace: { logLevel: 'info' // 'bug' | 'fatal' | 'error' | 'warning' | 'hint' | 'note' | 'suggestions' | 'info' }

Use more verbose levels like 'info' or 'suggestions' during development to understand what turbotrace is doing, but keep it at 'error' or 'warning' in production to avoid log noise.

logDetail - Controls whether turbotrace logs should include detailed analysis information. Default is false.

turbotrace: { logDetail: true }

Enable this when debugging dependency tracing issues or when you need to understand the specific details of what files are being analyzed.

logAll - Shows all log messages without limit. By default, turbotrace only shows 1 log message per category.

turbotrace: { logAll: true }

Useful for comprehensive debugging, but can generate significant log output in large projects.

contextDirectory - Controls the context directory for turbotrace analysis. Files outside this directory will not be traced.

turbotrace: { contextDirectory: '/path/to/your/project' }

This option has the same effect as setting outputFileTracingRoot. If both are set, experimental.turbotrace.contextDirectory takes precedence. Use this to limit tracing scope and improve performance by excluding unnecessary directories.

processCwd - Specifies the value of process.cwd() for tracing purposes when your code contains process.cwd() expressions.

turbotrace: { processCwd: '/path/to/working/directory' }

For example, if your code has require(process.cwd() + '/package.json'), turbotrace will trace it as require('/path/to/working/directory/package.json'). This ensures accurate dependency resolution when process.cwd() is used dynamically.

memoryLimit - Controls the maximum memory usage of turbotrace in MB. Default is 6000 MB (6 GB).

turbotrace: { memoryLimit: 4000 // Limit to 4 GB }

Adjust this based on your system's available memory and the size of your project. Larger projects with complex dependency graphs may need higher limits, while smaller projects or memory-constrained environments may benefit from lower limits.

Turbotrace significantly improves build performance for large Next.js applications by leveraging Rust's performance advantages for complex dependency analysis. Monitor your build times and memory usage when enabling this feature to ensure optimal configuration for your specific project needs.



6. urlImports

The urlImports feature allows you to import modules directly from external URLs instead of installing them locally. This experimental feature requires explicit configuration of trusted domains.

module.exports = { experimental: { urlImports: [ 'https://cdn.skypack.dev', 'https://esm.sh', 'https://cdn.jsdelivr.net', 'https://unpkg.com' ], }, }

Once configured, you can import modules directly from URLs:

// Import from Skypack CDN import confetti from 'https://cdn.skypack.dev/canvas-confetti' import { format } from 'https://cdn.skypack.dev/date-fns' // Import from esm.sh import React from 'https://esm.sh/react@18' // Use in components export default function CelebrationPage() { const celebrate = () => { confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }) } return ( <div> <h1>Today is {format(new Date(), 'MMMM do, yyyy')}</h1> <button onClick={celebrate}>Celebrate!</button> </div> ) }

URL imports work in various contexts:

// Static image imports import logo from 'https://example.com/assets/logo.png' // CSS imports import 'https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.min.css' // Dynamic imports const module = await import('https://cdn.skypack.dev/lodash-es') // Asset imports with import.meta.url const configUrl = new URL('https://example.com/config.json', import.meta.url) const config = await fetch(configUrl).then(r => r.json())

Next.js creates a lockfile system:

Security considerations:

The feature supports resources with Cache-Control: no-cache headers, which are fetched fresh on each build, making it suitable for dynamic configuration or frequently updated assets.