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
- Drop the `strategy` prop entirely: `afterInteractive` is the default and works everywhere.
- If it truly must be `beforeInteractive`, move the `<Script>` into `pages/_document.js` inside `<Head>`.
- 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
- Default to omitting `strategy` — `afterInteractive` covers almost every case.
- Reserve `beforeInteractive` for `pages/_document.js` only; document this in the repo.
- Run oxlint (nextjs plugin) in CI so a moved Script cannot keep the strategy silently.
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
- `next/script` components with inline content must specify an
- Prefer `next/script` component when using the inline script
- `<Document />` from `next/document` should not be imported o
- Do not include multiple instances of `<Head/>`
- Do not use `<head>` element. Use `<Head />` from `next/head`
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/cf66c81ad822f5da.
Report an issue: GitHub.