Next.js script optimization uses the <Script> component from next/script to load third-party analytics, tag managers, and chat widgets without blocking page rendering.
Dropping raw <script> tags into HTML often pauses parsing and hurts Core Web Vitals. The Next.js <Script> component lets you pick the exact moment each external script downloads and runs. You can place it in a shared layout or only on the specific routes that need it.
app/layout.tsxImport Script from next/script and attach a strategy prop matching how urgent that third-party tool is. Scripts placed in app/layout.tsx stay active across route transitions without downloading twice.
// app/layout.tsx
import Script from 'next/script';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://cdn.example.com/analytics.js"
strategy="afterInteractive"
/>
</body>
</html>
);
}
Next.js supports four script loading modes so heavy third-party libraries never slow down first paint or user clicks. Pick the lowest priority mode that still satisfies your tool's requirements.
| Strategy | Execution Timing | Best Use Case |
|---|---|---|
beforeInteractive |
Before page hydration starts | Bot protection, consent banners |
afterInteractive |
Immediately after hydration (default) | Analytics, conversion pixels |
lazyOnload |
During browser idle time | Live chat widgets, social embeds |
worker |
Off the main thread (experimental) | Heavy background telemetry |
Inline scripts require a unique id prop so Next.js can track and deduplicate execution across route changes. If you also need an onLoad or onError callback, wrap that <Script> inside a Client Component.
// app/components/MetricsScript.tsx
'use client';
import Script from 'next/script';
export default function MetricsScript() {
return (
<Script
id="metrics-init"
strategy="afterInteractive"
onLoad={() => {
console.info('Metrics script ready');
}}
>
{`
window.appMetrics = window.appMetrics || [];
window.appMetrics.push({ event: 'init' });
`}
</Script>
);
}
id on inline <Script> blocks: Next.js throws an error if an inline <Script> lacks a unique id string.beforeInteractive inside nested pages: beforeInteractive scripts only belong in the root app/layout.tsx file.onLoad handlers inside a Server Component: Event callbacks like onLoad or onReady only work inside 'use client' components.<Script> in Next.js?When you omit the strategy prop, Next.js uses afterInteractive by default so scripts run right after the page hydrates.
<Script> reload on every client-side <Link> navigation?No, scripts placed in app/layout.tsx load once and persist as users move between child pages.
lazyOnload instead of afterInteractive?Use lazyOnload for non-essential widgets like customer support chat bubbles that do not need to run during the first second of page load.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With