Impact: HIGH (200-800ms import cost reduction, faster builds and cold starts)
Barrel files (index.ts that re-exports everything) force bundlers to load entire libraries even when you only use one export. Icon and component libraries can have thousands of re-exports, adding megabytes to your client bundle. This is especially costly in Client Components where every byte ships to the browser.
Incorrect (imports entire library via barrel file):
'use client'// ❌ Loads all 1,500+ icons even though you use 3import { Check, X, Menu } from 'lucide-react'// ❌ Loads entire MUI libraryimport { Button, TextField } from '@mui/material'// ❌ Loads all of lodashimport { debounce, throttle } from 'lodash'
Correct (direct deep imports):
'use client'// ✅ Loads only the 3 icons you needimport Check from 'lucide-react/dist/esm/icons/check'import X from 'lucide-react/dist/esm/icons/x'import Menu from 'lucide-react/dist/esm/icons/menu'// ✅ Direct component importsimport Button from '@mui/material/Button'import TextField from '@mui/material/TextField'// ✅ Individual lodash function importsimport debounce from 'lodash/debounce'import throttle from 'lodash/throttle'
Best (Next.js optimizePackageImports):
// next.config.js — let Next.js handle it automaticallymodule.exports = { experimental: { optimizePackageImports: [ 'lucide-react', '@mui/material', '@mui/icons-material', 'lodash', 'date-fns', 'react-icons', '@radix-ui/react-icons', ], },}// Now barrel imports are automatically tree-shaken at build time:import { Check, X, Menu } from 'lucide-react' // ✅ Only loads 3 icons