oxc-project/oxc · warning · OxcDiagnostic

next/script's `beforeInteractive` strategy should not be use

Error message

next/script's `beforeInteractive` strategy should not be used outside of `pages/_document.js`

What it means

Warning from oxlint rule `nextjs/no-before-interactive-script-outside-document`. `strategy="beforeInteractive"` scripts must be injected into the initial HTML before hydration; in the pages router only `pages/_document.js` runs early enough to host them. Used anywhere else they break hydration or are silently degraded, so the rule reports the strategy outside `_document.js` (app-directory files are exempt).

Source

Thrown at crates/oxc_linter/src/rules/nextjs/no_before_interactive_script_outside_document.rs:17

use oxc_ast::{
    AstKind,
    ast::{JSXAttributeItem, JSXAttributeName, JSXAttributeValue},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;

use crate::{
    AstNode,
    context::LintContext,
    rule::Rule,
    utils::{get_next_script_import_local_name, is_document_page, is_in_app_dir},
};

fn no_before_interactive_script_outside_document_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("next/script's `beforeInteractive` strategy should not be used outside of `pages/_document.js`")
        .with_help("See https://nextjs.org/docs/messages/no-before-interactive-script-outside-document")
        .with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct NoBeforeInteractiveScriptOutsideDocument;

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Prevents the usage of `next/script`'s `beforeInteractive` strategy outside of `pages/_document.js`.
    /// This rule ensures that scripts with the `beforeInteractive` loading strategy are only used in the
    /// document component where they are most effective.
    ///
    /// ### Why is this bad?
    ///
    /// The `beforeInteractive` strategy is specifically designed to load scripts before any page hydration
    /// occurs, which is only guaranteed to work correctly when placed in `pages/_document.js`. Using it elsewhere:

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Drop the `strategy` prop entirely: `afterInteractive` is the default and works everywhere.
  2. If it truly must be `beforeInteractive`, move the `<Script>` into `pages/_document.js` inside `<Head>`.
  3. In the app router, render `next/script` with the default strategy in `app/layout.tsx` instead.

Example fix

// before (in pages/index.js)
<Script src="/vendor.js" strategy="beforeInteractive" />

// after
<Script src="/vendor.js" /> // afterInteractive is the default
Defensive patterns

Strategy: validation

Validate before calling

// find beforeInteractive usages outside _document.js:
// rg -n 'beforeInteractive' pages app components -g '!pages/_document.*'

Prevention

When it happens

Trigger: A `<Script>` element (local name from `next/script`) carrying `strategy="beforeInteractive"` in any file other than `pages/_document.js`, while the file is not in the app directory.

Common situations: Moving a critical script (font loader, bot detection, A/B testing) into a page or `_app.js`; copying vendor setup code that requests earliest possible loading.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/cf66c81ad822f5da. Report an issue: GitHub.