Best practices and guidelines for Turbopack, the Rust-powered incremental bundler for Next.js and modern web development
You are an expert in Turbopack, the incremental bundler optimized for JavaScript and TypeScript, written in Rust and built into Next.js. Follow these guidelines when working with Turbopack.
project/
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── globals.css
│ ├── components/ # Shared components
│ └── lib/ # Utility functions
├── public/ # Static assets
├── next.config.js # Next.js configuration
├── tsconfig.json # TypeScript config
└── package.json
# Next.js 13.4+
next dev --turbo
# Or in package.json
{
"scripts": {
"dev": "next dev --turbo"
}
}
// next.config.js
module.exports = {
experimental: {
turbo: {
// Turbopack-specific configuration
}
}
};
// next.config.js
module.exports = {
turbopack: {
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js'
},
'*.mdx': {
loaders: ['@mdx-js/loader']
}
}
}
};
// next.config.js
module.exports = {
turbopack: {
resolveAlias: {
'@components': './src/components',
'@lib': './src/lib',
'@styles': './src/styles'
}
}
};
// next.config.js
module.exports = {
turbopack: {
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js', '.json']
}
};
Turbopack has built-in support for:
.module.css filesNo loaders needed for:
css-loaderpostcss-loaderbabel-loader (for @babel/preset-env){
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@components/*": ["src/components/*"],
"@lib/*": ["src/lib/*"],
"@styles/*": ["src/styles/*"]
}
}
}
src/
├── components/
│ ├── atoms/ # Basic building blocks
│ │ ├── Button/
│ │ └── Input/
│ ├── molecules/ # Combinations of atoms
│ │ ├── SearchBar/
│ │ └── NavItem/
│ ├── organisms/ # Complex components
│ │ ├── Header/
│ │ └── Footer/
│ └── templates/ # Page layouts
│ └── MainLayout/
├── app/
│ └── page.tsx
└── lib/
└── utils.ts
Button/
├── Button.tsx
├── Button.module.css
├── Button.test.tsx
└── index.ts
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(() => import('@/components/HeavyComponent'), {
loading: () => <p>Loading...</p>,
ssr: false // Disable server-side rendering if needed
});
Next.js automatically code-splits by route in the app/ directory.
// Split large components
const ChartComponent = dynamic(() => import('./ChartComponent'));
const EditorComponent = dynamic(() => import('./EditorComponent'));
// Keep modules focused and small
// Changes to one module don't invalidate others
// Good: Separate concerns
export function formatDate(date: Date) { /* ... */ }
export function formatCurrency(amount: number) { /* ... */ }
// Avoid: Large utility files that change frequently
// Prefer specific imports
import { Button } from '@/components/Button';
// Avoid importing entire libraries
// Bad: import _ from 'lodash';
// Good: import debounce from 'lodash/debounce';
// Use const assertions for better tree-shaking
const ROUTES = {
home: '/',
about: '/about',
contact: '/contact'
} as const;
import styles from './Component.module.css';
function Component() {
return <div className={styles.container}>Content</div>;
}
// app/layout.tsx
import './globals.css';
// tailwind.config.js
module.exports = {
content: [
'./src/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}'
]
};
# .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
DATABASE_URL=postgresql://...
// Client-side (must have NEXT_PUBLIC_ prefix)
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
// Server-side only
const dbUrl = process.env.DATABASE_URL;
src/
├── components/
│ └── Button/
│ ├── Button.tsx
│ └── Button.test.tsx # Co-located test
└── __tests__/ # Integration tests
└── pages/
└── home.test.tsx
// Ensure correct tsconfig.json paths
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"] // Must match actual structure
}
}
}
# Clear Turbopack cache if issues arise
rm -rf .next
NEXT_DEBUG_TURBOPACK=1 next dev --turbo
# Check build output
ANALYZE=true next build
tsc --noEmit separately