Frontend Patterns

Pattern

Dynamic Import

Load modules asynchronously at runtime rather than bundling everything upfront.

Performance Advanced

Dynamic Import

Problem

Heavy dependencies load synchronously at startup even if they’re only needed for specific user actions. Date picker libraries, chart renderers, or PDF generators block initial page load despite most users never triggering the features that need them. The main bundle balloons with rarely-used utilities.

Solution

Load modules asynchronously when needed rather than bundling them upfront. This reduces initial bundle size and delays parsing costs until features are actually used.

Example

This example demonstrates loading a heavy chart library only when the user clicks to view charts, reducing the initial bundle size.

// Defer loading chart library until user requests it
button.addEventListener('click', async () => {
  // Dynamic import returns a promise - module loads asynchronously
  const Chart = await import('./chart.js');
  // Use the loaded module after it arrives
  new Chart.default(data);
});

Benefits

  • Reduces initial bundle size by loading code only when needed.
  • Improves time-to-interactive by deferring parsing of unused code.
  • Enables loading heavy dependencies only for users who need them.
  • Automatically creates code split points for bundlers.
  • Can significantly improve performance on slow networks.

Tradeoffs

  • Introduces loading delay when features are first accessed.
  • Requires handling loading states and potential failures.
  • Can complicate error handling with async module loading.
  • May create jarring UX if loading indicators aren’t well designed.
  • Harder to debug when dynamic imports fail to load.
Stay Updated

Get New Patterns
in Your Inbox

Join thousands of developers receiving weekly insights on frontend architecture patterns

No spam. Unsubscribe anytime.