Skip to content
C.W.K.
Stream
Lesson 07 of 08 · published

next/script

~18 min · next/script, loading strategy, third-party

Level 0Curious
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

Pick the loading strategy on purpose

StrategyWhen it loadsUse case
beforeInteractiveBefore hydrationCritical: bot detection, consent banners
afterInteractive (default)After hydrationAnalytics, tag managers
lazyOnloadDuring idle timeChat widgets, social embeds
workerIn a web workerHeavy compute that shouldn't block main thread

One rule

beforeInteractive is allowed only inside the root layout (it injects into the document head). Anywhere else it's a runtime error.

Choose a Script strategy from dependency order and user impact. Use beforeInteractive only for code that must precede hydration, default to afterInteractive for ordinary analytics, and defer nonessential widgets with lazyOnload. Give every script a stable identity. Verify that core content remains readable when a script fails or is blocked. An optional analytics or advertising script must not stop the application's own interactions.

Moving a third-party script later reduces contention but does not make it trustworthy or cheap. Consent, content security policy, failure isolation, data collection, and vendor downtime remain product concerns. Record the network waterfall and main-thread tasks with the script enabled, blocked, and slow. Verify hydration order, consent behavior, duplicate insertion across navigation, CSP violations, and that core interaction still works when the vendor never loads.

Code

Three loading strategies in one layout·tsx
import Script from 'next/script';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        {children}

        {/* analytics — after hydration */}
        <Script
          src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"
          strategy="afterInteractive"
        />

        {/* chat widget — during idle */}
        <Script
          src="https://widget.intercom.io/widget/abc123"
          strategy="lazyOnload"
        />

        {/* inline init — must be after the gtag script */}
        <Script id="gtag-init" strategy="afterInteractive">
          {`window.dataLayer = window.dataLayer || [];
            function gtag(){ dataLayer.push(arguments); }
            gtag('js', new Date());
            gtag('config', 'G-XXXXX');`}
        </Script>
      </body>
    </html>
  );
}

External links

Exercise

Audit a real Next.js app's third-party scripts. Reclassify any that don't need afterInteractive as lazyOnload and measure the impact on Time to Interactive.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.