You write a helper:
1// lib/payments.ts
2import Stripe from "stripe";
3
4export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
5
6export async function createCheckout(items: Item[]) {
7 return stripe.checkout.sessions.create({ /* … */ });
8}A teammate imports it into a Client Component. Now the Stripe secret key is referenced (and potentially logged) in client code, and the entire stripe Node SDK gets pulled into the browser bundle.
Add an import that fails at build time if the file is ever included in a client bundle:
1import "server-only"; // ← this line is enough
2import Stripe from "stripe";The build fails with:
Error: This module is marked with "server-only" and cannot be imported from a Client Component.
Equivalent on the other side:
1import "client-only";
2import confetti from "canvas-confetti";Use these on every sensitive boundary.
A Chart component that pulls in 200 KB of charting code should be loaded only when needed:
1"use client";
2import dynamic from "next/dynamic";
3
4const Chart = dynamic(() => import("./Chart"), {
5 ssr: false, // skip SSR (e.g., for canvas/three.js)
6 loading: () => <ChartSkeleton />,
7});
ssr: falsecannot be used in a Server Component. It's a client-side dynamic import.
1import { lazy, Suspense } from "react";
2const Mdx = lazy(() => import("./Mdx"));
3
4export default function Doc() {
5 return (
6 <Suspense fallback={<p>Loading…</p>}>
7 <Mdx />
8 </Suspense>
9 );
10}Each route segment is automatically code-split — you don't need to think about it. Importing HeavyComponent only in app/admin/page.tsx keeps it out of /dashboard's bundle.
1npx @next/bundle-analyzerOr use the built-in analyzer:
1// next.config.ts
2import withBundleAnalyzer from "@next/bundle-analyzer";
3
4const enable = process.env.ANALYZE === "true";
5
6export default withBundleAnalyzer({ enabled: enable })({
7 // …your config
8});1ANALYZE=true npm run buildAim for < 100 KB of JavaScript on a typical page (gzip). Above 150 KB, hydration starts to noticeably delay interactivity on mid-range mobile.
The biggest wins come from: