Skip to content

Conversation

@valentinpalkovic
Copy link
Contributor

@valentinpalkovic valentinpalkovic commented Sep 24, 2025

Closes #

What I did

I have removed the usage of next/config (runtime config) in Next.js versions 16 and above.
Related: https://github.com/vercel/next.js/pull/83944/files

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

core team members can create a canary release here or locally with gh workflow run --repo storybookjs/storybook canary-release-pr.yml --field pr=<PR_NUMBER>

Summary by CodeRabbit

  • New Features

    • Exposed a preview config for direct import in both Next.js and Next.js-Vite packages.
    • Version-aware preview setup: includes legacy preview only when running on Next.js < 16.
  • Refactor

    • Removed automatic side-effect loading of the preview config to streamline initialization.
  • Chores

    • Updated package exports/build outputs and added a dev dependency for version checks.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

Added browser build entries in nextjs and nextjs-vite to export ./config/preview from ./src/config/preview.ts with dts disabled and exposed in package exports. Introduced getNextjsVersion utility to read the installed Next.js version. Preset logic in both frameworks always includes the Storybook Next.js preview annotation and conditionally includes the config/preview annotation when Next.js < 16. Webpack config for Next.js now only adds the next/config alias and runtime config DefinePlugin for Next.js < 16. Removed side-effect imports of ./config/preview from preview.tsx files.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Dev as Developer
  participant Preset as Storybook Preset
  participant Utils as getNextjsVersion
  participant Ann as Annotation Builder

  Dev->>Preset: Initialize preset
  Preset->>Utils: Read installed Next.js version
  Utils-->>Preset: version (e.g., 15.x / 16.x)
  Preset->>Ann: Build annotations
  Note right of Ann #DDEBF7: Always include @storybook/nextjs/preview
  alt Next.js < 16.0.0
    Ann->>Ann: Add @storybook/nextjs/config/preview
  else Next.js >= 16.0.0
    Ann->>Ann: Do not add extra config preview
  end
  Ann-->>Preset: Final annotations
  Preset-->>Dev: Preset ready
Loading
sequenceDiagram
  autonumber
  participant Preset as Next.js Preset
  participant Utils as getNextjsVersion
  participant WP as Webpack Config

  Preset->>Utils: Determine Next.js version
  Utils-->>Preset: version
  Preset->>WP: Initialize webpack config
  alt Next.js < 16.0.0
    WP->>WP: Add alias('next/config') and set runtime config via DefinePlugin
    Note right of WP #FFF2CC: Legacy runtime behavior retained
  else Next.js >= 16.0.0
    WP->>WP: Skip alias and runtime config define
    Note right of WP #E6F4EA: Behavior gated for 16+
  end
  WP-->>Preset: Final webpack config
Loading

Suggested reviewers

  • ndelangen
  • kylegach

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title accurately reflects the primary change by indicating the removal of next/config usage for projects running Next.js version 16 and above, which aligns with the conditional imports and configuration updates in the diff. It is concise, specific to the framework and version, and avoids unnecessary details or vague language.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch valentin/drop-support-for-next-config-in-Next-v16

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a9f873 and c2f498a.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (2)
  • code/frameworks/nextjs-vite/package.json (2 hunks)
  • code/frameworks/nextjs/src/preset.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • code/frameworks/nextjs-vite/package.json
  • code/frameworks/nextjs/src/preset.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Comment @coderabbitai help to get the list of available commands and usage tips.

@valentinpalkovic valentinpalkovic added nextjs maintenance User-facing maintenance tasks ci:normal labels Sep 24, 2025
@nx-cloud
Copy link

nx-cloud bot commented Sep 24, 2025

View your CI Pipeline Execution ↗ for commit c2f498a

Command Status Duration Result
nx run-many -t build --parallel=3 ✅ Succeeded 47s View ↗

☁️ Nx Cloud last updated this comment at 2025-09-26 08:16:26 UTC

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
code/frameworks/nextjs/package.json (2)

82-116: Add dependency on @storybook/nextjs-vite (required by preset annotations).

This package imports @storybook/nextjs-vite/preview and @storybook/nextjs-vite/config/preview at runtime. Without a declared dep, consumers installing only @storybook/nextjs will hit module resolution failures.

Apply this diff to add the dependency:

   "dependencies": {
     "@babel/core": "^7.24.4",
@@
     "@storybook/builder-webpack5": "workspace:*",
     "@storybook/preset-react-webpack": "workspace:*",
     "@storybook/react": "workspace:*",
+    "@storybook/nextjs-vite": "workspace:*",
     "@types/semver": "^7.3.4",

129-131: Extend Next peer range to include v16.

Code paths explicitly support Next.js 16+, but the peer range excludes it, causing npm/yarn peer warnings or installs to fail in strict setups.

Apply this diff:

-    "next": "^14.1.0 || ^15.0.0",
+    "next": "^14.1.0 || ^15.0.0 || ^16.0.0",
code/frameworks/nextjs-vite/package.json (2)

82-87: Declare semver as a runtime dependency.

Used by src/preset.ts; relying on hoisting will break consumers.

Apply this diff:

   "dependencies": {
     "@storybook/builder-vite": "workspace:*",
     "@storybook/react": "workspace:*",
     "@storybook/react-vite": "workspace:*",
+    "semver": "^7.3.5",
     "styled-jsx": "5.1.6",
     "vite-plugin-storybook-nextjs": "^2.0.7"
   },

95-100: Extend Next peer range to include v16.

Aligns peer contract with new behavior and gating logic.

Apply this diff:

-    "next": "^14.1.0 || ^15.0.0",
+    "next": "^14.1.0 || ^15.0.0 || ^16.0.0",
🧹 Nitpick comments (1)
code/frameworks/nextjs-vite/src/utils.ts (1)

6-7: Cache the Next.js version to avoid repeated sync fs reads.

Minor optimization; avoids multiple disk hits in multi-call scenarios.

Apply this diff:

-export const getNextjsVersion = (): string =>
-  JSON.parse(readFileSync(join(resolvePackageDir('next'), 'package.json'), 'utf8')).version;
+let __cachedNextVersion: string | undefined;
+export const getNextjsVersion = (): string => {
+  if (!__cachedNextVersion) {
+    __cachedNextVersion = JSON.parse(
+      readFileSync(join(resolvePackageDir('next'), 'package.json'), 'utf8')
+    ).version;
+  }
+  return __cachedNextVersion;
+};
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b9ff97 and a529cbe.

📒 Files selected for processing (10)
  • code/frameworks/nextjs-vite/build-config.ts (1 hunks)
  • code/frameworks/nextjs-vite/package.json (1 hunks)
  • code/frameworks/nextjs-vite/src/preset.ts (2 hunks)
  • code/frameworks/nextjs-vite/src/preview.tsx (1 hunks)
  • code/frameworks/nextjs-vite/src/utils.ts (1 hunks)
  • code/frameworks/nextjs/build-config.ts (1 hunks)
  • code/frameworks/nextjs/package.json (1 hunks)
  • code/frameworks/nextjs/src/config/webpack.ts (3 hunks)
  • code/frameworks/nextjs/src/preset.ts (1 hunks)
  • code/frameworks/nextjs/src/preview.tsx (0 hunks)
💤 Files with no reviewable changes (1)
  • code/frameworks/nextjs/src/preview.tsx
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Group related mocks together

Applied to files:

  • code/frameworks/nextjs-vite/package.json
  • code/frameworks/nextjs-vite/build-config.ts
  • code/frameworks/nextjs/package.json
  • code/frameworks/nextjs/build-config.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies

Applied to files:

  • code/frameworks/nextjs-vite/package.json
  • code/frameworks/nextjs-vite/build-config.ts
  • code/frameworks/nextjs/package.json
  • code/frameworks/nextjs/build-config.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required dependencies that the test subject uses

Applied to files:

  • code/frameworks/nextjs-vite/package.json
  • code/frameworks/nextjs-vite/build-config.ts
  • code/frameworks/nextjs/build-config.ts
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors

Applied to files:

  • code/frameworks/nextjs-vite/package.json
  • code/frameworks/nextjs-vite/build-config.ts
  • code/frameworks/nextjs/build-config.ts
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Keep mock implementations simple and focused

Applied to files:

  • code/frameworks/nextjs-vite/build-config.ts
  • code/frameworks/nextjs/build-config.ts
📚 Learning: 2025-09-24T09:39:39.209Z
Learnt from: ndelangen
PR: storybookjs/storybook#32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.209Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • code/frameworks/nextjs-vite/build-config.ts
  • code/frameworks/nextjs-vite/src/preview.tsx
  • code/frameworks/nextjs/build-config.ts
🧬 Code graph analysis (4)
code/frameworks/nextjs-vite/src/utils.ts (1)
code/core/src/shared/utils/module.ts (1)
  • resolvePackageDir (27-32)
code/frameworks/nextjs-vite/src/preset.ts (1)
code/frameworks/nextjs-vite/src/utils.ts (1)
  • getNextjsVersion (6-7)
code/frameworks/nextjs/src/preset.ts (2)
code/frameworks/nextjs-vite/src/utils.ts (1)
  • getNextjsVersion (6-7)
code/frameworks/nextjs/src/utils.ts (1)
  • getNextjsVersion (24-25)
code/frameworks/nextjs/src/config/webpack.ts (1)
code/frameworks/nextjs/src/utils.ts (2)
  • getNextjsVersion (24-25)
  • addScopedAlias (71-75)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: normal
  • GitHub Check: Danger JS
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (7)
code/frameworks/nextjs/package.json (1)

38-38: Add export for ./config/preview — LGTM

Public export aligns with new build entry. No concerns.

code/frameworks/nextjs-vite/src/preview.tsx (1)

5-5: Removal of unused type and side-effect import — LGTM

Type import narrowed correctly; side-effect loading now handled via preset annotations.

Please confirm Next < 16 still loads @storybook/nextjs-vite/config/preview via the updated preset.

code/frameworks/nextjs-vite/build-config.ts (1)

14-18: New browser entry for ./config/preview — LGTM

Export surface matches package exports; dts disabled as expected.

code/frameworks/nextjs-vite/package.json (1)

38-38: Add export for ./config/preview — LGTM

Matches build entry; no types mapping expected (dts disabled).

code/frameworks/nextjs/build-config.ts (1)

14-18: New browser entry for ./config/preview — LGTM

Consistent with added export; dts:false appropriate.

code/frameworks/nextjs/src/config/webpack.ts (2)

68-79: Guarded __NEXT_RUNTIME_CONFIG define (LGTM)

Defining process.env.__NEXT_RUNTIME_CONFIG only for Next < 16 is correct and matches the intent to drop it on 16+.


4-4: Confirmed: semver is a runtime dependency for the package that ships this file

code/frameworks/nextjs/package.json lists dependencies.semver = ^7.3.5 — no change required.

Comment on lines +40 to +51
const annotations = [
...entry,
fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/preview')),
];

const nextjsVersion = getNextjsVersion();
const isNext16orNewer = semver.gte(nextjsVersion, '16.0.0');

// TODO: Remove this once we only support Next.js v16 and above
if (!isNext16orNewer) {
annotations.push(fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/config/preview')));
}
Copy link
Contributor

@coderabbitai coderabbitai bot Sep 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Treat 16 prereleases (canary/rc) as >=16 when gating behavior.

semver.gte('16.0.0-canary.1', '16.0.0') is false. You likely want canaries/RCs to opt into the v16 path.

Apply this diff:

-  const nextjsVersion = getNextjsVersion();
-  const isNext16orNewer = semver.gte(nextjsVersion, '16.0.0');
+  const nextjsVersion = getNextjsVersion();
+  const coerced = semver.coerce(nextjsVersion)?.version ?? nextjsVersion;
+  const isNext16orNewer = semver.gte(coerced, '16.0.0');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const annotations = [
...entry,
fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/preview')),
];
const nextjsVersion = getNextjsVersion();
const isNext16orNewer = semver.gte(nextjsVersion, '16.0.0');
// TODO: Remove this once we only support Next.js v16 and above
if (!isNext16orNewer) {
annotations.push(fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/config/preview')));
}
const annotations = [
...entry,
fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/preview')),
];
const nextjsVersion = getNextjsVersion();
const coerced = semver.coerce(nextjsVersion)?.version ?? nextjsVersion;
const isNext16orNewer = semver.gte(coerced, '16.0.0');
// TODO: Remove this once we only support Next.js v16 and above
if (!isNext16orNewer) {
annotations.push(fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/config/preview')));
}
🤖 Prompt for AI Agents
In code/frameworks/nextjs-vite/src/preset.ts around lines 40 to 51, the semver
check treats prerelease Next.js versions (canary/rc) as older than 16.0.0;
change the gating to treat prereleases as >=16 by calling
semver.gte(nextjsVersion, '16.0.0', { includePrerelease: true }) when computing
isNext16orNewer so canary/rc versions opt into the v16 path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines +4 to +10
import semver from 'semver';
import type { Configuration as WebpackConfig } from 'webpack';

import { addScopedAlias, resolveNextConfig } from '../utils';
import { addScopedAlias, getNextjsVersion, resolveNextConfig } from '../utils';

const nextjsVersion = getNextjsVersion();
const isNext16orNewer = semver.gte(nextjsVersion, '16.0.0');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid import-time Next version resolution; include canary prereleases in the check

Reading the installed Next version at module import time can throw in environments where Next isn’t present (e.g., build/test of this package in isolation). Compute this lazily and be tolerant to absence. Also treat 16.0.0 prereleases (e.g., canary) as “>=16”.

Apply this diff to make the check resilient and prerelease-aware:

-const nextjsVersion = getNextjsVersion();
-const isNext16orNewer = semver.gte(nextjsVersion, '16.0.0');
+let isNext16orNewer = false;
+try {
+  const nextjsVersion = getNextjsVersion();
+  // Include prereleases like 16.0.0-canary.X as >= 16
+  isNext16orNewer = semver.satisfies(nextjsVersion, '>=16.0.0-0');
+} catch {
+  // If Next isn't resolvable (e.g., during isolated builds/tests), default to legacy behavior (<16)
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import semver from 'semver';
import type { Configuration as WebpackConfig } from 'webpack';
import { addScopedAlias, resolveNextConfig } from '../utils';
import { addScopedAlias, getNextjsVersion, resolveNextConfig } from '../utils';
const nextjsVersion = getNextjsVersion();
const isNext16orNewer = semver.gte(nextjsVersion, '16.0.0');
import semver from 'semver';
import type { Configuration as WebpackConfig } from 'webpack';
import { addScopedAlias, getNextjsVersion, resolveNextConfig } from '../utils';
let isNext16orNewer = false;
try {
const nextjsVersion = getNextjsVersion();
// Include prereleases like 16.0.0-canary.X as >= 16
isNext16orNewer = semver.satisfies(nextjsVersion, '>=16.0.0-0');
} catch {
// If Next isn't resolvable (e.g., during isolated builds/tests), default to legacy behavior (<16)
}
🤖 Prompt for AI Agents
In code/frameworks/nextjs/src/config/webpack.ts around lines 4 to 10, avoid
resolving the installed Next.js version at module import time and make the >=16
check tolerant to missing Next and prereleases: replace the top-level
nextjsVersion/isNext16orNewer constants with a small lazy helper (e.g., function
isNext16orNewer()) that calls getNextjsVersion() inside a try/catch, treats
missing or errored resolution as a safe low version (e.g., "0.0.0"), and uses
semver.gte(version, '16.0.0', { includePrerelease: true }) (or equivalent semver
API) to treat canary/prerelease versions as >=16; update any call sites to
invoke the helper instead of using the import-time boolean.

Comment on lines +29 to +32
// TODO: Remove this once we only support Next.js 16 and above
if (!isNext16orNewer) {
addScopedAlias(baseConfig, 'next/config');
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Version‑gate the next/config alias (LGTM)

Conditionally aliasing next/config only for Next < 16 aligns with the upstream removal.

Run this to ensure no unconditional imports of next/config remain elsewhere:


🏁 Script executed:

#!/bin/bash
# Find any imports/requires of next/config and show context
rg -nP -C2 '(?:from\s+["'\'']next/config["'\'']|require\(\s*["'\'']next/config["'\'']\s*\))' \
  --type=ts --type=tsx --type=js --type=jsx -g '!**/node_modules/**' code

Length of output: 27


🏁 Script executed:

#!/bin/bash
set -euo pipefail

pattern="(?:from\s+['\"]next/config['\"]|require\\(\\s*['\"]next/config['\"]\\s*\\)|import\\(\\s*['\"]next/config['\"]\\s*\\))"

rg -nP -C2 "$pattern" \
  -g 'code/**/*.ts' -g 'code/**/*.tsx' -g 'code/**/*.js' -g 'code/**/*.jsx' -g '!code/**/node_modules/**' -S || true

Length of output: 475


Unconditional imports of next/config remain — fix required

Direct imports found at:

  • code/frameworks/nextjs/src/config/preview.ts
  • code/frameworks/nextjs-vite/src/config/preview.ts

Gate these imports/use behind the Next <16 check (or convert to a dynamic require used only when Next <16) so runtime/builds on Next ≥16 don't reference the removed module, or make the webpack alias unconditional.

Comment on lines 51 to 54
const annotations = [
...entry,
fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/preview')),
];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Cross-package import requires dependency.

Using @storybook/nextjs-vite/preview from @storybook/nextjs means @storybook/nextjs must declare a dep on @storybook/nextjs-vite (not rely on monorepo hoisting).

Dependency addition is proposed in code/frameworks/nextjs/package.json.

🤖 Prompt for AI Agents
In code/frameworks/nextjs/src/preset.ts around lines 51 to 54, the file imports
'@storybook/nextjs-vite/preview' directly which requires that @storybook/nextjs
declare an explicit dependency on @storybook/nextjs-vite; update
code/frameworks/nextjs/package.json to add "@storybook/nextjs-vite" (with the
appropriate version or workspace spec) to dependencies (not devDependencies) so
the package no longer relies on monorepo hoisting, then run install and update
lockfile so the import resolves correctly.

Comment on lines 56 to 64
const nextjsVersion = getNextjsVersion();
const isNext16orNewer = semver.gte(nextjsVersion, '16.0.0');

// TODO: Remove this once we only support Next.js v16 and above
if (!isNext16orNewer) {
annotations.push(fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/config/preview')));
}

return annotations;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Missing import for getNextjsVersion and prerelease handling.

  • getNextjsVersion is used but not imported — this will fail at runtime.
  • Treat Next 16 prereleases as >=16.

Apply these diffs:

Add import near the other local imports:

+import { getNextjsVersion } from './utils';

Improve the semver check:

-  const nextjsVersion = getNextjsVersion();
-  const isNext16orNewer = semver.gte(nextjsVersion, '16.0.0');
+  const nextjsVersion = getNextjsVersion();
+  const coerced = semver.coerce(nextjsVersion)?.version ?? nextjsVersion;
+  const isNext16orNewer = semver.gte(coerced, '16.0.0');

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Check: semver imported in nextjs-vite preset"
rg -nP "from ['\"]semver['\"]" code/frameworks/nextjs-vite/src/preset.ts || true

echo "Check: semver present in nextjs-vite/package.json dependencies"
rg -nP '"dependencies"\s*:\s*\{[\s\S]*"semver"' -n code/frameworks/nextjs-vite/package.json || true

echo "Check: nextjs preset references @storybook/nextjs-vite paths"
rg -nP "@storybook/nextjs-vite/(preview|config/preview)" code/frameworks/nextjs/src/preset.ts

echo "Check: @storybook/nextjs declares dep on @storybook/nextjs-vite"
rg -nP '"@storybook/nextjs-vite"\s*:\s*' code/frameworks/nextjs/package.json || true

echo "Check: getNextjsVersion imported in nextjs preset"
rg -nP 'import\s*\{\s*getNextjsVersion\s*\}\s*from\s*[\'"]./utils[\'"]' code/frameworks/nextjs/src/preset.ts || true

echo "Check: peer next range includes ^16 in both packages"
rg -nP '"next"\s*:\s*".*\^16' code/frameworks/nextjs/package.json code/frameworks/nextjs-vite/package.json || true

Length of output: 563


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "==== nextjs preset content ===="
sed -n '1,240p' code/frameworks/nextjs/src/preset.ts || true

echo
echo "==== search for getNextjsVersion occurrences (definition and imports) ===="
rg -n --hidden 'getNextjsVersion' || true

echo
echo "==== files exporting getNextjsVersion ===="
rg -n --hidden 'export .*getNextjsVersion|export function getNextjsVersion' || true

echo
echo "==== show candidate utils files under nextjs ===="
rg -n --hidden 'getNextjsVersion' code/frameworks/nextjs -S || true

echo
echo "==== semver import in nextjs preset ===="
rg -nP "from ['\"]semver['\"]" code/frameworks/nextjs/src/preset.ts || true

echo
echo "==== semver import in project ===="
rg -nP "from ['\"]semver['\"]" || true

echo
echo "==== show nextjs package.json ===="
sed -n '1,240p' code/frameworks/nextjs/package.json || true

echo
echo "==== show nextjs-vite package.json ===="
sed -n '1,240p' code/frameworks/nextjs-vite/package.json || true

Length of output: 21767


Add missing import and treat Next 16 prereleases as >=16

previewAnnotations calls getNextjsVersion but there is no static import — add the import and coerce prerelease versions before semver.gte so Next 16 prereleases count as >=16.

+import { getNextjsVersion } from './utils';
-  const nextjsVersion = getNextjsVersion();
-  const isNext16orNewer = semver.gte(nextjsVersion, '16.0.0');
+  const nextjsVersion = getNextjsVersion();
+  const coerced = semver.coerce(nextjsVersion)?.version ?? nextjsVersion;
+  const isNext16orNewer = semver.gte(coerced, '16.0.0');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const nextjsVersion = getNextjsVersion();
const isNext16orNewer = semver.gte(nextjsVersion, '16.0.0');
// TODO: Remove this once we only support Next.js v16 and above
if (!isNext16orNewer) {
annotations.push(fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/config/preview')));
}
return annotations;
import { getNextjsVersion } from './utils';
const nextjsVersion = getNextjsVersion();
const coerced = semver.coerce(nextjsVersion)?.version ?? nextjsVersion;
const isNext16orNewer = semver.gte(coerced, '16.0.0');
// TODO: Remove this once we only support Next.js v16 and above
if (!isNext16orNewer) {
annotations.push(fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/config/preview')));
}
return annotations;
🤖 Prompt for AI Agents
In code/frameworks/nextjs/src/preset.ts around lines 56 to 64, add a static
import for getNextjsVersion at the top of the file and normalize prerelease
Next.js versions before comparison so Next 16 prereleases count as >=16;
specifically, call getNextjsVersion(), coerce/normalize the returned version
(e.g. via semver.coerce or equivalent to strip prerelease metadata) and use that
normalized value with semver.gte(nextVersionNormalized, '16.0.0') when setting
isNext16orNewer, keeping the rest of the logic unchanged.

@storybook-app-bot
Copy link

storybook-app-bot bot commented Sep 24, 2025

Package Benchmarks

Commit: c2f498a, ran on 26 September 2025 at 08:05:17 UTC

The following packages have significant changes to their size or dependencies:

@storybook/addon-docs

Before After Difference
Dependency count 18 18 0
Self size 2.07 MB 2.06 MB 🎉 -10 KB 🎉
Dependency size 9.44 MB 9.43 MB 🎉 -10 KB 🎉
Bundle Size Analyzer Link Link

@storybook/addon-vitest

Before After Difference
Dependency count 6 6 0
Self size 501 KB 491 KB 🎉 -10 KB 🎉
Dependency size 1.53 MB 1.53 MB 0 B
Bundle Size Analyzer Link Link

@storybook/builder-vite

Before After Difference
Dependency count 11 11 0
Self size 330 KB 319 KB 🎉 -10 KB 🎉
Dependency size 1.30 MB 1.30 MB 🚨 +18 B 🚨
Bundle Size Analyzer Link Link

@storybook/html-vite

Before After Difference
Dependency count 14 14 0
Self size 23 KB 23 KB 0 B
Dependency size 1.67 MB 1.66 MB 🎉 -10 KB 🎉
Bundle Size Analyzer Link Link

@storybook/nextjs

Before After Difference
Dependency count 531 531 0
Self size 950 KB 940 KB 🎉 -10 KB 🎉
Dependency size 58.43 MB 58.41 MB 🎉 -21 KB 🎉
Bundle Size Analyzer Link Link

@storybook/nextjs-vite

Before After Difference
Dependency count 124 124 0
Self size 4.01 MB 4.09 MB 🚨 +71 KB 🚨
Dependency size 21.62 MB 21.59 MB 🎉 -31 KB 🎉
Bundle Size Analyzer Link Link

@storybook/preact-vite

Before After Difference
Dependency count 14 14 0
Self size 14 KB 14 KB 🎉 -18 B 🎉
Dependency size 1.65 MB 1.64 MB 🎉 -10 KB 🎉
Bundle Size Analyzer Link Link

@storybook/react-native-web-vite

Before After Difference
Dependency count 157 157 0
Self size 31 KB 31 KB 🎉 -24 B 🎉
Dependency size 23.01 MB 22.97 MB 🎉 -31 KB 🎉
Bundle Size Analyzer Link Link

@storybook/react-vite

Before After Difference
Dependency count 114 114 0
Self size 37 KB 37 KB 🚨 +24 B 🚨
Dependency size 19.56 MB 19.53 MB 🎉 -31 KB 🎉
Bundle Size Analyzer Link Link

@storybook/react-webpack5

Before After Difference
Dependency count 272 272 0
Self size 25 KB 25 KB 0 B
Dependency size 43.35 MB 43.33 MB 🎉 -21 KB 🎉
Bundle Size Analyzer Link Link

@storybook/svelte-vite

Before After Difference
Dependency count 19 19 0
Self size 59 KB 59 KB 0 B
Dependency size 26.79 MB 26.78 MB 🎉 -10 KB 🎉
Bundle Size Analyzer Link Link

@storybook/sveltekit

Before After Difference
Dependency count 20 20 0
Self size 58 KB 58 KB 🚨 +30 B 🚨
Dependency size 26.85 MB 26.84 MB 🎉 -10 KB 🎉
Bundle Size Analyzer Link Link

@storybook/vue3-vite

Before After Difference
Dependency count 109 109 0
Self size 38 KB 38 KB 0 B
Dependency size 43.78 MB 43.77 MB 🎉 -10 KB 🎉
Bundle Size Analyzer Link Link

@storybook/web-components-vite

Before After Difference
Dependency count 15 15 0
Self size 20 KB 20 KB 🎉 -18 B 🎉
Dependency size 1.70 MB 1.68 MB 🎉 -10 KB 🎉
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 187 187 0
Self size 901 KB 890 KB 🎉 -11 KB 🎉
Dependency size 79.76 MB 79.76 MB 🎉 -660 B 🎉
Bundle Size Analyzer Link Link

@storybook/react-dom-shim

Before After Difference
Dependency count 0 0 0
Self size 22 KB 12 KB 🎉 -10 KB 🎉
Dependency size 785 B 785 B 0 B
Bundle Size Analyzer Link Link

@storybook/preset-create-react-app

Before After Difference
Dependency count 68 68 0
Self size 36 KB 26 KB 🎉 -10 KB 🎉
Dependency size 5.97 MB 5.97 MB 0 B
Bundle Size Analyzer Link Link

@storybook/react

Before After Difference
Dependency count 2 2 0
Self size 894 KB 884 KB 🎉 -10 KB 🎉
Dependency size 28 KB 18 KB 🎉 -10 KB 🎉
Bundle Size Analyzer Link Link

@ndelangen ndelangen merged commit b81780a into next Sep 26, 2025
56 of 57 checks passed
@ndelangen ndelangen deleted the valentin/drop-support-for-next-config-in-Next-v16 branch September 26, 2025 11:52
@github-actions github-actions bot mentioned this pull request Sep 26, 2025
16 tasks
ndelangen added a commit that referenced this pull request Oct 15, 2025
…next-config-in-Next-v16

Next.js: Remove next/config usage in Next.js >=v16 projects

(cherry picked from commit b81780a)
@coderabbitai coderabbitai bot mentioned this pull request Oct 16, 2025
13 tasks
@github-actions github-actions bot added the patch:done Patch/release PRs already cherry-picked to main/release branch label Oct 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:normal maintenance User-facing maintenance tasks nextjs patch:done Patch/release PRs already cherry-picked to main/release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants