billing hacks

Dynamic Imports

Load code only when needed. Modals, charts, and heavy components don't belong in your initial bundle.

TL;DR

Use dynamic() for modals, charts, and heavy components. Load on user action (click, scroll) or feature access. Use ssr: false for browser-only libraries.

The Basic Pattern

import dynamic from 'next/dynamic';

// Instead of: import HeavyChart from '@/components/HeavyChart';
const HeavyChart = dynamic(() => import('@/components/HeavyChart'));

Now HeavyChart loads in a separate chunk, downloaded only when rendered.

With Loading State

const HeavyChart = dynamic(
  () => import('@/components/HeavyChart'),
  {
    loading: () => <div className="h-64 animate-pulse bg-gray-200" />,
  }
);

Client-Only Components

Some components use window or document and can't render on the server:

const MapComponent = dynamic(
  () => import('@/components/Map'),
  { ssr: false }
);

ssr: false means no SEO for that content. Fine for maps and widgets. Bad for main content.

When to Use Dynamic Imports

Component TypeDynamic?Why
Modals/dialogsYesNot visible initially
Charts/graphsYesHeavy, usually below fold
Rich text editorsYesVery heavy, few users need it
NavigationNoNeeded immediately
Hero sectionNoAbove fold, needs SEO
Auth formsMaybeIf behind a click

Pattern: Lazy Modal

'use client';

import { useState } from 'react';
import dynamic from 'next/dynamic';

const SettingsModal = dynamic(() => import('./SettingsModal'));

export function SettingsButton() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <button onClick={() => setOpen(true)}>Settings</button>
      {open && <SettingsModal onClose={() => setOpen(false)} />}
    </>
  );
}

Modal code only downloads when button is clicked.

Pattern: Load on Scroll

'use client';

import { useEffect, useState, useRef } from 'react';
import dynamic from 'next/dynamic';

const HeavySection = dynamic(() => import('./HeavySection'));

export function LazySection() {
  const [visible, setVisible] = useState(false);
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setVisible(true);
          observer.disconnect();
        }
      },
      { rootMargin: '100px' }
    );

    if (ref.current) observer.observe(ref.current);
    return () => observer.disconnect();
  }, []);

  return (
    <div ref={ref}>
      {visible ? <HeavySection /> : <Skeleton />}
    </div>
  );
}

Component loads 100px before it scrolls into view.

Pattern: Feature-Gated Loading

import dynamic from 'next/dynamic';

const AdminPanel = dynamic(() => import('./AdminPanel'));

export default function Dashboard({ user }) {
  return (
    <div>
      <MainContent />
      {user.role === 'admin' && <AdminPanel />}
    </div>
  );
}

Regular users never download admin code.

Pattern: Conditional Heavy Library

'use client';

import { useState } from 'react';

export function ExportButton({ data }) {
  const [exporting, setExporting] = useState(false);

  const handleExport = async () => {
    setExporting(true);

    // Import xlsx only when needed (500KB+ library)
    const XLSX = await import('xlsx');
    const worksheet = XLSX.utils.json_to_sheet(data);
    const workbook = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(workbook, worksheet, 'Data');
    XLSX.writeFile(workbook, 'export.xlsx');

    setExporting(false);
  };

  return (
    <button onClick={handleExport} disabled={exporting}>
      {exporting ? 'Exporting...' : 'Export to Excel'}
    </button>
  );
}

The xlsx library only loads when someone actually exports.

Key Takeaways

Dynamic import all modals Modal code shouldn't load until the user clicks to open.

Lazy load charts and graphs Heavy visualization libraries should load on-demand.

Import heavy libraries conditionally Use inline await import() for xlsx, pdf-lib, etc.

Load below-fold on scroll Use IntersectionObserver to trigger imports as content approaches viewport.

Gate admin/premium features Don't ship code for features most users will never access.


Next: SSR Patterns - understand server vs client components.

On this page