Skip to main content
The next/script component lets you load and manage third-party scripts with built-in loading strategies that optimize performance.

Basic usage

Import Script from next/script and add it to any layout or page:
import Script from 'next/script'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>{children}</body>
      <Script src="https://example.com/script.js" />
    </html>
  )
}

Loading strategies

The strategy prop controls when the script loads relative to the page lifecycle.
Loads the script after the page becomes interactive. This is the default and is suitable for most third-party scripts that don’t need to run before the page is usable.
app/page.tsx
import Script from 'next/script'

export default function Page() {
  return (
    <>
      <Script
        src="https://example.com/script.js"
        strategy="afterInteractive"
      />
    </>
  )
}
Use for: Analytics, tag managers, chatbots.
Loads the script during browser idle time, after all page resources have been fetched. Use for scripts that don’t need to load early.
app/page.tsx
import Script from 'next/script'

export default function Page() {
  return (
    <>
      <Script
        src="https://example.com/script.js"
        strategy="lazyOnload"
      />
    </>
  )
}
Use for: Low-priority scripts, social share buttons, feedback widgets.
Loads the script before any Next.js code and before page hydration. This strategy must be placed in the root layout (app/layout).
app/layout.tsx
import Script from 'next/script'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>{children}</body>
      <Script
        src="https://example.com/script.js"
        strategy="beforeInteractive"
      />
    </html>
  )
}
Use for: Bot detection scripts, consent managers, polyfills that must run before any other code.
beforeInteractive blocks the page from becoming interactive until the script loads. Only use it for scripts that are truly critical before hydration.
Loads the script in a web worker using Partytown. This offloads heavy third-party scripts from the main thread.Enable the feature first in next.config.js:
next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    nextScriptWorkers: true,
  },
}

module.exports = nextConfig
app/page.tsx
import Script from 'next/script'

export default function Page() {
  return (
    <Script
      src="https://example.com/script.js"
      strategy="worker"
    />
  )
}
Use for: Analytics, ad scripts, and other heavy third-party scripts you want off the main thread.

Inline scripts

For small inline scripts, use the Script component with either a string or JSX children:
import Script from 'next/script'

export default function Page() {
  return (
    <>
      {/* Inline script with dangerouslySetInnerHTML */}
      <Script
        id="inline-script"
        dangerouslySetInnerHTML={{
          __html: `
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
          `,
        }}
      />

      {/* Inline script as JSX children */}
      <Script id="another-script">
        {`console.log('Hello from inline script')`}
      </Script>
    </>
  )
}
Inline scripts require a unique id prop so Next.js can track and optimize them.

Event handlers

Use event handler props to execute code at different points of the script lifecycle:
onLoad
function
Fires once when the script has finished loading. Cannot be used with beforeInteractive.
<Script
  src="https://example.com/script.js"
  onLoad={() => {
    console.log('Script loaded')
  }}
/>
onReady
function
Fires after the script loads and every time the component mounts. Useful for re-running script initialization when navigating between pages.
<Script
  src="https://example.com/script.js"
  onReady={() => {
    // Re-initialize widget after each navigation
  }}
/>
onError
function
Fires when the script fails to load. Cannot be used with beforeInteractive.
<Script
  src="https://example.com/script.js"
  onError={(e) => {
    console.error('Script failed to load', e)
  }}
/>

Props reference

src
string
URL of the external script. Required unless dangerouslySetInnerHTML or children are used.
strategy
string
default:"'afterInteractive'"
The loading strategy. One of 'beforeInteractive', 'afterInteractive', 'lazyOnload', or 'worker'.
id
string
Required for inline scripts (those using dangerouslySetInnerHTML or children).
nonce
string
A cryptographic nonce for Content Security Policy support.

Build docs developers (and LLMs) love