From 4095107fd39711b4a875cf67a9173ceb4cfb38c5 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 22 Jan 2026 01:11:27 -0700 Subject: [PATCH 1/5] docs: add skill for updating Next.js documentation (#88656) ### What? Adds a new Claude Code skill `/update-docs` that guides maintainers through updating Next.js documentation based on code changes. ### Why? To help ensure PRs include complete and accurate documentation updates by providing a structured workflow, code-to-docs mappings, and quick reference materials for Next.js doc conventions. ### How? The skill includes: - Main workflow in `SKILL.md` with step-by-step guidance for analyzing changes, updating docs, and scaffolding new feature documentation - `references/DOC-CONVENTIONS.md` - Complete frontmatter schema, code block formatting, and MDX component usage - `references/CODE-TO-DOCS-MAPPING.md` - Maps source code directories to their corresponding documentation paths ### Usage **Manual invocation:** ``` /update-docs ``` **Automatic triggers** - the skill activates when you mention: - "update documentation for my changes" - "check docs for this PR" - "what docs need updating" - "sync docs with code" - "scaffold docs for this feature" - "document this feature" - "review docs completeness" - "add docs for this change" - "what documentation is affected" - "docs impact" - References to `docs/`, `docs/01-app`, `docs/02-pages`, or `.mdx files` --- .claude/skills/update-docs/SKILL.md | 264 ++++++++++++++++++ .../references/CODE-TO-DOCS-MAPPING.md | 136 +++++++++ .../update-docs/references/DOC-CONVENTIONS.md | 236 ++++++++++++++++ 3 files changed, 636 insertions(+) create mode 100644 .claude/skills/update-docs/SKILL.md create mode 100644 .claude/skills/update-docs/references/CODE-TO-DOCS-MAPPING.md create mode 100644 .claude/skills/update-docs/references/DOC-CONVENTIONS.md diff --git a/.claude/skills/update-docs/SKILL.md b/.claude/skills/update-docs/SKILL.md new file mode 100644 index 0000000000000..638e020b8dd36 --- /dev/null +++ b/.claude/skills/update-docs/SKILL.md @@ -0,0 +1,264 @@ +--- +name: update-docs +description: This skill should be used when the user asks to "update documentation for my changes", "check docs for this PR", "what docs need updating", "sync docs with code", "scaffold docs for this feature", "document this feature", "review docs completeness", "add docs for this change", "what documentation is affected", "docs impact", or mentions "docs/", "docs/01-app", "docs/02-pages", "MDX", "documentation update", "API reference", ".mdx files". Provides guided workflow for updating Next.js documentation based on code changes. +--- + +# Next.js Documentation Updater + +Guides you through updating Next.js documentation based on code changes on the active branch. Designed for maintainers reviewing PRs for documentation completeness. + +## Quick Start + +1. **Analyze changes**: Run `git diff canary...HEAD --stat` to see what files changed +2. **Identify affected docs**: Map changed source files to documentation paths +3. **Review each doc**: Walk through updates with user confirmation +4. **Validate**: Run `pnpm lint` to check formatting +5. **Commit**: Stage documentation changes + +## Workflow: Analyze Code Changes + +### Step 1: Get the diff + +```bash +# See all changed files on this branch +git diff canary...HEAD --stat + +# See changes in specific areas +git diff canary...HEAD -- packages/next/src/ +``` + +### Step 2: Identify documentation-relevant changes + +Look for changes in these areas: + +| Source Path | Likely Doc Impact | +| -------------------------------------- | --------------------------- | +| `packages/next/src/client/components/` | Component API reference | +| `packages/next/src/server/` | Function API reference | +| `packages/next/src/shared/lib/` | Varies by export | +| `packages/next/src/build/` | Configuration or build docs | +| `packages/next/src/lib/` | Various features | + +### Step 3: Map to documentation files + +Use the code-to-docs mapping in `references/CODE-TO-DOCS-MAPPING.md` to find corresponding documentation files. + +Example mappings: + +- `src/client/components/image.tsx` → `docs/01-app/03-api-reference/02-components/image.mdx` +- `src/server/config-shared.ts` → `docs/01-app/03-api-reference/05-config/` + +## Workflow: Update Existing Documentation + +### Step 1: Read the current documentation + +Before making changes, read the existing doc to understand: + +- Current structure and sections +- Frontmatter fields in use +- Whether it uses `` / `` for router-specific content + +### Step 2: Identify what needs updating + +Common updates include: + +- **New props/options**: Add to the props table and create a section explaining usage +- **Changed behavior**: Update descriptions and examples +- **Deprecated features**: Add deprecation notices and migration guidance +- **New examples**: Add code blocks following conventions + +### Step 3: Apply updates with confirmation + +For each change: + +1. Show the user what you plan to change +2. Wait for confirmation before editing +3. Apply the edit +4. Move to the next change + +### Step 4: Check for shared content + +If the doc uses the `source` field pattern (common for Pages Router docs), the source file is the one to edit. Example: + +```yaml +# docs/02-pages/... file with shared content +--- +source: app/building-your-application/optimizing/images +--- +``` + +Edit the App Router source, not the Pages Router file. + +### Step 5: Validate changes + +```bash +pnpm lint # Check formatting +pnpm prettier-fix # Auto-fix formatting issues +``` + +## Workflow: Scaffold New Feature Documentation + +Use this when adding documentation for entirely new features. + +### Step 1: Determine the doc type + +| Feature Type | Doc Location | Template | +| ------------------- | --------------------------------------------------- | ---------------- | +| New component | `docs/01-app/03-api-reference/02-components/` | API Reference | +| New function | `docs/01-app/03-api-reference/04-functions/` | API Reference | +| New config option | `docs/01-app/03-api-reference/05-config/` | Config Reference | +| New concept/guide | `docs/01-app/02-guides/` | Guide | +| New file convention | `docs/01-app/03-api-reference/03-file-conventions/` | File Convention | + +### Step 2: Create the file with proper naming + +- Use kebab-case: `my-new-feature.mdx` +- Add numeric prefix if ordering matters: `05-my-new-feature.mdx` +- Place in the correct directory based on feature type + +### Step 3: Use the appropriate template + +**API Reference Template:** + +```mdx +--- +title: Feature Name +description: Brief description of what this feature does. +--- + +{/* The content of this doc is shared between the app and pages router. You can use the `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */} + +Brief introduction to the feature. + +## Reference + +### Props + +
+ +| Prop | Example | Type | Status | +| ----------------------- | ------------------ | ------ | -------- | +| [`propName`](#propname) | `propName="value"` | String | Required | + +
+ +#### `propName` + +Description of the prop. + +\`\`\`tsx filename="app/example.tsx" switcher +// TypeScript example +\`\`\` + +\`\`\`jsx filename="app/example.js" switcher +// JavaScript example +\`\`\` +``` + +**Guide Template:** + +```mdx +--- +title: How to do X in Next.js +nav_title: X +description: Learn how to implement X in your Next.js application. +--- + +Introduction explaining why this guide is useful. + +## Prerequisites + +What the reader needs to know before starting. + +## Step 1: First Step + +Explanation and code example. + +\`\`\`tsx filename="app/example.tsx" switcher +// Code example +\`\`\` + +## Step 2: Second Step + +Continue with more steps... + +## Next Steps + +Related topics to explore. +``` + +### Step 4: Add related links + +Update frontmatter with related documentation: + +```yaml +related: + title: Next Steps + description: Learn more about related features. + links: + - app/api-reference/functions/related-function + - app/guides/related-guide +``` + +## Documentation Conventions + +See `references/DOC-CONVENTIONS.md` for complete formatting rules. + +### Quick Reference + +**Frontmatter (required):** + +```yaml +--- +title: Page Title (2-3 words) +description: One or two sentences describing the page. +--- +``` + +**Code blocks:** + +``` +\`\`\`tsx filename="app/page.tsx" switcher +// TypeScript first +\`\`\` + +\`\`\`jsx filename="app/page.js" switcher +// JavaScript second +\`\`\` +``` + +**Router-specific content:** + +```mdx +Content only for App Router docs. + +Content only for Pages Router docs. +``` + +**Notes:** + +```mdx +> **Good to know**: Single line note. + +> **Good to know**: +> +> - Multi-line note point 1 +> - Multi-line note point 2 +``` + +## Validation Checklist + +Before committing documentation changes: + +- [ ] Frontmatter has `title` and `description` +- [ ] Code blocks have `filename` attribute +- [ ] TypeScript examples use `switcher` with JS variant +- [ ] Props tables are properly formatted +- [ ] Related links point to valid paths +- [ ] `pnpm lint` passes +- [ ] Changes render correctly (if preview available) + +## References + +- `references/DOC-CONVENTIONS.md` - Complete frontmatter and formatting rules +- `references/CODE-TO-DOCS-MAPPING.md` - Source code to documentation mapping diff --git a/.claude/skills/update-docs/references/CODE-TO-DOCS-MAPPING.md b/.claude/skills/update-docs/references/CODE-TO-DOCS-MAPPING.md new file mode 100644 index 0000000000000..46405a1d77b74 --- /dev/null +++ b/.claude/skills/update-docs/references/CODE-TO-DOCS-MAPPING.md @@ -0,0 +1,136 @@ +# Code to Documentation Mapping + +Maps Next.js source code directories to their corresponding documentation files. + +## Core Mappings + +### Components + +| Source Path | Documentation Path | +| ------------------------------------------------ | ------------------------------------------------------- | +| `packages/next/src/client/components/image.tsx` | `docs/01-app/03-api-reference/02-components/image.mdx` | +| `packages/next/src/client/components/link.tsx` | `docs/01-app/03-api-reference/02-components/link.mdx` | +| `packages/next/src/client/components/script.tsx` | `docs/01-app/03-api-reference/02-components/script.mdx` | +| `packages/next/src/client/components/form.tsx` | `docs/01-app/03-api-reference/02-components/form.mdx` | + +### Functions + +| Source Path | Documentation Path | +| ---------------------------------------------------- | ----------------------------------------------------------------- | +| `packages/next/src/server/request/` | `docs/01-app/03-api-reference/04-functions/` | +| `packages/next/src/server/lib/metadata/` | `docs/01-app/03-api-reference/04-functions/generate-metadata.mdx` | +| `packages/next/src/client/components/navigation.tsx` | `docs/01-app/03-api-reference/04-functions/use-router.mdx` | +| `packages/next/src/client/components/navigation.tsx` | `docs/01-app/03-api-reference/04-functions/use-pathname.mdx` | +| `packages/next/src/client/components/navigation.tsx` | `docs/01-app/03-api-reference/04-functions/use-search-params.mdx` | + +### File Conventions + +| Source Path | Documentation Path | +| ------------------------------------------ | ------------------------------------------------------------- | +| `packages/next/src/build/webpack/loaders/` | `docs/01-app/03-api-reference/03-file-conventions/` | +| `packages/next/src/server/app-render/` | `docs/01-app/03-api-reference/03-file-conventions/layout.mdx` | +| `packages/next/src/server/app-render/` | `docs/01-app/03-api-reference/03-file-conventions/page.mdx` | + +### Configuration + +| Source Path | Documentation Path | +| ------------------------------------------- | ----------------------------------------------------------- | +| `packages/next/src/server/config-shared.ts` | `docs/01-app/03-api-reference/05-config/01-next-config-js/` | +| `packages/next/src/server/config.ts` | `docs/01-app/03-api-reference/05-config/01-next-config-js/` | +| `packages/next/src/build/webpack-config.ts` | `docs/01-app/03-api-reference/05-config/01-next-config-js/` | + +### Directives + +| Source Path | Documentation Path | +| ---------------------------------------- | ----------------------------------------------------------- | +| `packages/next/src/server/use-cache/` | `docs/01-app/03-api-reference/01-directives/use-cache.mdx` | +| `packages/next/src/client/use-client.ts` | `docs/01-app/03-api-reference/01-directives/use-client.mdx` | +| `packages/next/src/server/use-server.ts` | `docs/01-app/03-api-reference/01-directives/use-server.mdx` | + +### Metadata File Conventions + +| Source Path | Documentation Path | +| --------------------------------- | ---------------------------------------------------------------------------------- | +| `packages/next/src/lib/metadata/` | `docs/01-app/03-api-reference/03-file-conventions/01-metadata/` | +| Metadata icons handling | `docs/01-app/03-api-reference/03-file-conventions/01-metadata/app-icons.mdx` | +| Open Graph images | `docs/01-app/03-api-reference/03-file-conventions/01-metadata/opengraph-image.mdx` | +| Sitemap generation | `docs/01-app/03-api-reference/03-file-conventions/01-metadata/sitemap.mdx` | + +## Directory Pattern Mappings + +### By Feature Area + +| Source Directory | Documentation Area | Notes | +| -------------------------------------- | --------------------------------------------- | ---------------------- | +| `packages/next/src/client/` | `docs/01-app/03-api-reference/02-components/` | Client-side components | +| `packages/next/src/server/` | `docs/01-app/03-api-reference/04-functions/` | Server functions | +| `packages/next/src/build/` | `docs/01-app/03-api-reference/05-config/` | Build configuration | +| `packages/next/src/shared/lib/router/` | `docs/01-app/02-guides/` | Routing guides | +| `packages/next/src/lib/metadata/` | `docs/01-app/02-guides/metadata/` | Metadata guides | + +### CLI Commands + +| Source Path | Documentation Path | +| ------------------------------------- | ---------------------------------------------------- | +| `packages/next/src/cli/next-dev.ts` | `docs/01-app/03-api-reference/06-cli/next-dev.mdx` | +| `packages/next/src/cli/next-build.ts` | `docs/01-app/03-api-reference/06-cli/next-build.mdx` | +| `packages/next/src/cli/next-start.ts` | `docs/01-app/03-api-reference/06-cli/next-start.mdx` | + +## Finding Related Documentation + +### Step 1: Identify the changed export + +Look at what's exported from the changed file: + +- Public API exports → API Reference docs +- Internal utilities → Usually no docs needed +- Configuration types → Config docs + +### Step 2: Search for existing docs + +Use Claude's built-in tools for searching: + +- **Find docs mentioning a term**: Use the Grep tool with the pattern and `docs/` as the path +- **List docs in a directory**: Use the Glob tool with pattern like `docs/01-app/03-api-reference/04-functions/*.mdx` + +### Step 3: Check for shared content + +If editing App Router docs, check if Pages Router has a corresponding file with `source` field: + +- **Find source references**: Use the Grep tool with pattern `source: app/api-reference` in `docs/02-pages/` + +## Common Patterns + +### New API Function + +1. Export added to `packages/next/src/server/` +2. Create doc at `docs/01-app/03-api-reference/04-functions/function-name.mdx` +3. Update index/listing pages if applicable + +### New Component Prop + +1. Prop added to component in `packages/next/src/client/components/` +2. Update the props table in corresponding doc +3. Add a section explaining the new prop with examples + +### New Config Option + +1. Option added to `packages/next/src/server/config-shared.ts` +2. Find the relevant config doc in `docs/01-app/03-api-reference/05-config/01-next-config-js/` +3. Add the option with description and example + +### Behavioral Change + +1. Logic changed in any source file +2. Find all docs that describe this behavior +3. Update descriptions and examples to match new behavior +4. Add migration notes if breaking change + +## Quick Search Commands + +Use Claude's built-in tools for efficient searching: + +- **Find all docs mentioning a term**: Use the Grep tool with your search pattern and `docs/` as the path, filtering to `*.mdx` files +- **List all API reference docs**: Use the Glob tool with pattern `docs/01-app/03-api-reference/**/*.mdx` +- **Find docs by filename pattern**: Use the Glob tool with pattern like `docs/**/*image*.mdx` +- **Read a doc's frontmatter**: Use the Read tool with a line limit to check the `source` field diff --git a/.claude/skills/update-docs/references/DOC-CONVENTIONS.md b/.claude/skills/update-docs/references/DOC-CONVENTIONS.md new file mode 100644 index 0000000000000..8c0f4af81dbec --- /dev/null +++ b/.claude/skills/update-docs/references/DOC-CONVENTIONS.md @@ -0,0 +1,236 @@ +# Next.js Documentation Conventions + +Complete reference for frontmatter schema, code block formatting, and MDX component usage. + +## Frontmatter Schema + +All MDX files must start with YAML frontmatter enclosed in `---` delimiters. + +### Required Fields + +| Field | Description | Example | +| ------------- | ------------------------------------------- | ------------------------------------------------ | +| `title` | Page title for SEO and headings (2-3 words) | `title: Image Component` | +| `description` | Brief description (1-2 sentences) | `description: Optimize images using next/image.` | + +### Optional Fields + +| Field | Description | Example | +| ----------- | -------------------------------------------------- | -------------------------------------------- | +| `nav_title` | Shorter title for navigation sidebar | `nav_title: Image` | +| `source` | Pull content from another page (avoid duplication) | `source: app/api-reference/components/image` | +| `related` | Next steps section with related links | See below | +| `version` | Development stage indicator | `version: experimental` | + +### Related Links Format + +```yaml +--- +title: My Feature +description: Description here. +related: + title: Next Steps + description: Learn more about related features. + links: + - app/api-reference/components/image + - app/guides/optimizing/images +--- +``` + +### Version Field Values + +- `experimental` - Experimental feature, may change +- `legacy` - Legacy feature, consider alternatives +- `unstable` - Unstable API, not recommended for production +- `RC` - Release candidate + +## Code Block Conventions + +### Basic Syntax + +```` +```language filename="path/to/file.ext" +code here +``` +```` + +### Required Attributes + +| Attribute | When to Use | Example | +| ----------- | --------------------------------- | ------------------------- | +| `filename` | Always for code examples | `filename="app/page.tsx"` | +| `switcher` | When providing TS and JS variants | `switcher` | +| `highlight` | To highlight specific lines | `highlight={1,3-5}` | + +### TypeScript/JavaScript Switcher Pattern + +Always provide TypeScript first, then JavaScript: + +````mdx +```tsx filename="app/page.tsx" switcher +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'My Page', +} +``` + +```jsx filename="app/page.js" switcher +export const metadata = { + title: 'My Page', +} +``` +```` + +### Terminal Commands + +Use `bash` language without filename: + +````mdx +```bash +npm install next +``` +```` + +### Highlighting Lines + +``` +highlight={1} # Single line +highlight={1,3} # Multiple lines +highlight={1-5} # Range +highlight={1,3-5,8} # Combined +``` + +## MDX Components + +### AppOnly / PagesOnly + +Use for router-specific content in shared documentation: + +```mdx + + +This content only appears in App Router documentation. + + + + + +This content only appears in Pages Router documentation. + + +``` + +**Important:** Include blank lines inside the components for proper markdown parsing. + +### Image Component + +For themed images with light/dark variants: + +```mdx +Description of the image +``` + +### Notes and Callouts + +**Single line:** + +```mdx +> **Good to know**: Important information here. +``` + +**Multi-line:** + +```mdx +> **Good to know**: +> +> - First point +> - Second point +> - Third point +``` + +## Props Tables + +Use HTML table wrapper for horizontal scroll on mobile: + +```mdx +
+ +| Prop | Example | Type | Status | +| ----------------- | ------------------- | ------- | -------- | +| [`src`](#src) | `src="/image.png"` | String | Required | +| [`alt`](#alt) | `alt="Description"` | String | Required | +| [`width`](#width) | `width={500}` | Integer | - | + +
+``` + +### Status Values + +- `Required` - Must be provided +- `-` - Optional +- `Deprecated` - Will be removed, use alternative + +## Shared Content Pattern + +For Pages Router docs that share content with App Router: + +**App Router (source):** `docs/01-app/03-api-reference/02-components/image.mdx` + +- Contains the full documentation +- Uses `` and `` for router-specific sections + +**Pages Router (consumer):** `docs/02-pages/03-api-reference/01-components/image.mdx` + +```yaml +--- +title: Image Component +description: Optimize images using next/image. +source: app/api-reference/components/image +--- +``` + +The `source` field pulls content from the App Router doc. + +## Writing Style + +### Voice + +- **Guides:** Instructional, use "you" to address users +- **API Reference:** Technical, use imperative verbs ("create", "pass", "return") + +### Clarity + +- Use plain words over complex alternatives +- Be specific: "the `src` prop" not "this prop" +- Avoid jargon unless explaining it + +### Structure + +Typical page structure: + +1. Brief introduction (what and why) +2. Minimal working example +3. Detailed reference/options +4. Examples for different use cases +5. Related links (via frontmatter) + +## File Naming + +- Use kebab-case: `generate-metadata.mdx` +- Add numeric prefix for ordering: `01-installation.mdx` +- Index pages: `index.mdx` + +## Validation Commands + +```bash +pnpm lint # Full lint check +pnpm prettier-fix # Fix formatting +pnpm types # TypeScript check +``` From acd5d5edda97f263818b7bc5606f31afb4e785dc Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Thu, 22 Jan 2026 01:37:23 -0700 Subject: [PATCH 2/5] Turbopack: [chore] Fix Rust check warnings (#88871) # What? Fix some unimportant `check` warnings that appear as noise in the build logs. --- crates/napi/src/next_api/turbopack_ctx.rs | 2 +- turbopack/crates/turbopack-cli/benches/small_apps.rs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/napi/src/next_api/turbopack_ctx.rs b/crates/napi/src/next_api/turbopack_ctx.rs index 3b018273c77a6..dbdeb0f134070 100644 --- a/crates/napi/src/next_api/turbopack_ctx.rs +++ b/crates/napi/src/next_api/turbopack_ctx.rs @@ -158,7 +158,7 @@ pub struct NapiNextTurbopackCallbacks { throw_turbopack_internal_error: ThreadsafeFunction, } -/// Arguments for [`NapiNextTurbopackCallbacks::throw_turbopack_internal_error`]. +/// Arguments for `NapiNextTurbopackCallbacks::throw_turbopack_internal_error`. #[napi(object)] pub struct TurbopackInternalErrorOpts { pub message: String, diff --git a/turbopack/crates/turbopack-cli/benches/small_apps.rs b/turbopack/crates/turbopack-cli/benches/small_apps.rs index 49fada9a3ff82..0d072be73ea43 100644 --- a/turbopack/crates/turbopack-cli/benches/small_apps.rs +++ b/turbopack/crates/turbopack-cli/benches/small_apps.rs @@ -3,10 +3,7 @@ #[global_allocator] static ALLOC: turbo_tasks_malloc::TurboMalloc = turbo_tasks_malloc::TurboMalloc; -use std::{ - path::{Path, PathBuf}, - process::Command, -}; +use std::path::{Path, PathBuf}; use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use turbopack_cli::arguments::{BuildArguments, CommonArguments}; From 37ac3974db79adc7d8da7923f09df6d1509986e4 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 22 Jan 2026 12:11:53 +0100 Subject: [PATCH 3/5] stabilize browser log forward options (#88857) --- .../browserDebugInfoInTerminal.mdx | 126 ++---------------- .../05-config/01-next-config-js/logging.mdx | 62 ++++++++- packages/next/src/build/define-env.ts | 2 +- packages/next/src/server/config-schema.ts | 3 + packages/next/src/server/config-shared.ts | 11 ++ packages/next/src/server/config.ts | 31 +++++ .../server/dev/browser-logs/receive-logs.ts | 14 +- .../src/server/dev/browser-logs/source-map.ts | 10 +- .../src/server/dev/hot-reloader-turbopack.ts | 6 +- .../src/server/dev/hot-reloader-webpack.ts | 6 +- .../browser-logs/browser-logs.test.ts | 98 ++------------ .../browser-logs/fixtures/next.config.js | 5 + 12 files changed, 146 insertions(+), 228 deletions(-) create mode 100644 test/development/browser-logs/fixtures/next.config.js diff --git a/docs/01-app/03-api-reference/05-config/01-next-config-js/browserDebugInfoInTerminal.mdx b/docs/01-app/03-api-reference/05-config/01-next-config-js/browserDebugInfoInTerminal.mdx index 4a0e853f601fb..db6aca4aa11e4 100644 --- a/docs/01-app/03-api-reference/05-config/01-next-config-js/browserDebugInfoInTerminal.mdx +++ b/docs/01-app/03-api-reference/05-config/01-next-config-js/browserDebugInfoInTerminal.mdx @@ -1,134 +1,34 @@ --- title: browserDebugInfoInTerminal description: Forward browser console logs and errors to your terminal during development. -version: experimental +redirect: /docs/app/api-reference/config/next-config-js/logging#browser-console-logs --- -The `experimental.browserDebugInfoInTerminal` option forwards console output and runtime errors originating in the browser to the dev server terminal. +This configuration option has been moved to [`logging.browserToTerminal`](/docs/app/api-reference/config/next-config-js/logging#browser-console-logs). -This option is disabled by default. When enabled it only works in development mode. +## Migration -## Usage +To migrate to the new configuration, replace `experimental.browserDebugInfoInTerminal` with `logging.browserToTerminal`: -Enable forwarding: - -```ts filename="next.config.ts" switcher -import type { NextConfig } from 'next' - -const nextConfig: NextConfig = { - experimental: { - browserDebugInfoInTerminal: true, - }, -} - -export default nextConfig -``` - -```js filename="next.config.js" switcher -/** @type {import('next').NextConfig} */ -const nextConfig = { +```js filename="next.config.js" +// Before +module.exports = { experimental: { browserDebugInfoInTerminal: true, }, } -module.exports = nextConfig -``` - -### Serialization limits - -Deeply nested objects/arrays are truncated using **sensible defaults**. You can tweak these limits: - -- **depthLimit**: (optional) Limit stringification depth for nested objects/arrays. Default: 5 -- **edgeLimit**: (optional) Max number of properties or elements to include per object or array. Default: 100 - -```ts filename="next.config.ts" switcher -import type { NextConfig } from 'next' - -const nextConfig: NextConfig = { - experimental: { - browserDebugInfoInTerminal: { - depthLimit: 5, - edgeLimit: 100, - }, - }, -} - -export default nextConfig -``` - -```js filename="next.config.js" switcher -/** @type {import('next').NextConfig} */ -const nextConfig = { - experimental: { - browserDebugInfoInTerminal: { - depthLimit: 5, - edgeLimit: 100, - }, - }, -} - -module.exports = nextConfig -``` - -### Source location - -Source locations are included by default when this feature is enabled. - -```tsx filename="app/page.tsx" highlight={8} -'use client' - -export default function Home() { - return ( - - ) -} -``` - -Clicking the button prints this message to the terminal. - -```bash filename="Terminal" -[browser] Hello World (app/page.tsx:8:17) -``` - -To suppress them, set `showSourceLocation: false`. - -- **showSourceLocation**: Include source location info when available. - -```ts filename="next.config.ts" switcher -import type { NextConfig } from 'next' - -const nextConfig: NextConfig = { - experimental: { - browserDebugInfoInTerminal: { - showSourceLocation: false, - }, +// After +module.exports = { + logging: { + browserToTerminal: true, }, } - -export default nextConfig ``` -```js filename="next.config.js" switcher -/** @type {import('next').NextConfig} */ -const nextConfig = { - experimental: { - browserDebugInfoInTerminal: { - showSourceLocation: false, - }, - }, -} - -module.exports = nextConfig -``` +The new `logging.browserToTerminal` option supports the log level values (`true`, `'warn'`, `'error'`). Note that the object configuration options (`depthLimit`, `edgeLimit`, `showSourceLocation`) are no longer available in the new configuration. | Version | Changes | | --------- | ---------------------------------------------------- | | `v15.4.0` | experimental `browserDebugInfoInTerminal` introduced | +| `v16.2.x` | Moved to stable as `logging.browserToTerminal` | diff --git a/docs/01-app/03-api-reference/05-config/01-next-config-js/logging.mdx b/docs/01-app/03-api-reference/05-config/01-next-config-js/logging.mdx index a5551a5575547..f00e08bfb0aec 100644 --- a/docs/01-app/03-api-reference/05-config/01-next-config-js/logging.mdx +++ b/docs/01-app/03-api-reference/05-config/01-next-config-js/logging.mdx @@ -1,6 +1,6 @@ --- title: logging -description: Configure how data fetches are logged to the console when running Next.js in development mode. +description: Configure logging behavior in the terminal when running Next.js in development mode. --- {/* The content of this doc is shared between the app and pages router. You can use the `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */} @@ -11,8 +11,6 @@ description: Configure how data fetches are logged to the console when running N You can configure the logging level and whether the full URL is logged to the console when running Next.js in development mode. -Currently, `logging` only applies to data fetching using the `fetch` API. It does not yet apply to other logs inside of Next.js. - ```js filename="next.config.js" module.exports = { logging: { @@ -60,6 +58,64 @@ module.exports = { } ``` +### Browser Console Logs + +You can forward browser console logs (such as `console.log`, `console.warn`, `console.error`) to the terminal during development. This is useful for debugging client-side code without needing to check the browser's developer tools. + +```js filename="next.config.js" +module.exports = { + logging: { + browserToTerminal: true, + }, +} +``` + +#### Options + +The `browserToTerminal` option accepts the following values: + +| Value | Description | +| --------- | --------------------------------------------------- | +| `'warn'` | Forward only warnings and errors, by default | +| `'error'` | Forward only errors | +| `true` | Forward all console output (log, info, warn, error) | +| `false` | Disable browser log forwarding | + +```js filename="next.config.js" +module.exports = { + logging: { + browserToTerminal: 'warn', + }, +} +``` + +#### Source Location + +When enabled, browser logs include source location information (file path and line number) by default. For example: + +```tsx filename="app/page.tsx" highlight={8} +'use client' + +export default function Home() { + return ( + + ) +} +``` + +Clicking the button prints this message to the terminal: + +```bash filename="Terminal" +[browser] Hello World (app/page.tsx:8:17) +``` + ### Disabling Logging In addition, you can disable the development logging by setting `logging` to `false`. diff --git a/packages/next/src/build/define-env.ts b/packages/next/src/build/define-env.ts index 40e3f656feeb0..a2cafd4d8260b 100644 --- a/packages/next/src/build/define-env.ts +++ b/packages/next/src/build/define-env.ts @@ -332,7 +332,7 @@ export function getDefineEnv({ : {}), 'process.env.__NEXT_BROWSER_DEBUG_INFO_IN_TERMINAL': JSON.stringify( - config.experimental.browserDebugInfoInTerminal || false + (config.logging && config.logging.browserToTerminal) || false ), 'process.env.__NEXT_MCP_SERVER': !!config.experimental.mcpServer, diff --git a/packages/next/src/server/config-schema.ts b/packages/next/src/server/config-schema.ts index c62ef896ffb77..eaeaa2a6b5019 100644 --- a/packages/next/src/server/config-schema.ts +++ b/packages/next/src/server/config-schema.ts @@ -626,6 +626,9 @@ export const configSchema: zod.ZodType = z.lazy(() => }), ]) .optional(), + browserToTerminal: z + .union([z.boolean(), z.enum(['error', 'warn'])]) + .optional(), }), z.literal(false), ]) diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index 6519f151636e1..f379b71275bb2 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -268,6 +268,15 @@ export interface LoggingConfig { * You can specify a pattern to match incoming requests that should not be logged. */ incomingRequests?: boolean | IncomingRequestLoggingConfig + + /** + * Forward browser console logs to terminal. + * - `false`: Disable browser log forwarding + * - `true`: Forward all browser console output to terminal + * - `'warn'`: Forward warnings and errors to terminal + * - `'error'`: Forward only errors to terminal + */ + browserToTerminal?: boolean | 'error' | 'warn' } export interface ExperimentalConfig { @@ -773,6 +782,8 @@ export interface ExperimentalConfig { * - `true`: Same as 'verbose' - forward all browser console output to terminal * - `false`: Disable browser log forwarding to terminal * - Object: Enable with custom configuration + * + * @deprecated Use `logging.browserToTerminal` instead. */ browserDebugInfoInTerminal?: | boolean diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index cbf6c14f5461d..8fe9a9cf6d188 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -195,6 +195,16 @@ function checkDeprecations( ) } } + + // browserDebugInfoInTerminal has moved to logging.browserToTerminal + if (userConfig.experimental?.browserDebugInfoInTerminal !== undefined) { + warnOptionHasBeenDeprecated( + userConfig, + 'experimental.browserDebugInfoInTerminal', + `\`experimental.browserDebugInfoInTerminal\` has been moved to \`logging.browserToTerminal\`. Please update your ${configFileName} file accordingly.`, + silent + ) + } } export function warnOptionHasBeenMovedOutOfExperimental( @@ -374,6 +384,27 @@ function assignDefaultsAndValidate( result.experimental.trustHostHeader = true } + // Normalize experimental.browserDebugInfoInTerminal to logging.browserToTerminal + if ( + result.logging !== false && + result.experimental?.browserDebugInfoInTerminal !== undefined + ) { + const loggingConfig = result.logging || {} + if (!('browserToTerminal' in loggingConfig)) { + const expConfig = result.experimental.browserDebugInfoInTerminal + // Convert object config to simple format (level or true) + const normalizedValue = + typeof expConfig === 'object' && expConfig !== null + ? (expConfig.level ?? true) + : expConfig + + result.logging = { + ...loggingConfig, + browserToTerminal: normalizedValue, + } + } + } + if ( result.experimental?.allowDevelopmentBuild && process.env.NODE_ENV !== 'development' diff --git a/packages/next/src/server/dev/browser-logs/receive-logs.ts b/packages/next/src/server/dev/browser-logs/receive-logs.ts index 2eebff31f89a3..012525f840a55 100644 --- a/packages/next/src/server/dev/browser-logs/receive-logs.ts +++ b/packages/next/src/server/dev/browser-logs/receive-logs.ts @@ -447,10 +447,7 @@ async function handleDefaultConsole( type LogLevel = 'error' | 'warn' | 'verbose' -type BrowserLogConfig = - | boolean - | LogLevel - | { level?: LogLevel; showSourceLocation?: boolean } +type BrowserLogConfig = boolean | 'error' | 'warn' // Log levels from most severe to least severe // Lower index = more severe @@ -487,14 +484,7 @@ function shouldShowEntry( } // Determine the effective minimum log level - const minLevel: LogLevel = - typeof config === 'string' - ? config - : config === true - ? 'verbose' // true means show everything - : typeof config === 'object' - ? (config.level ?? 'verbose') // object config defaults to verbose for backward compatibility - : 'warn' // default for new installations + const minLevel: LogLevel = typeof config === 'string' ? config : 'verbose' // true means show everything const minPriority = LOG_LEVEL_PRIORITY[minLevel] diff --git a/packages/next/src/server/dev/browser-logs/source-map.ts b/packages/next/src/server/dev/browser-logs/source-map.ts index 6804600bf1069..34670b4c3ecb1 100644 --- a/packages/next/src/server/dev/browser-logs/source-map.ts +++ b/packages/next/src/server/dev/browser-logs/source-map.ts @@ -261,16 +261,8 @@ export const withLocation = async ( }, ctx: MappingContext, distDir: string, - config: - | boolean - | 'error' - | 'warn' - | 'verbose' - | { level?: 'error' | 'warn' | 'verbose'; showSourceLocation?: boolean } + _config: boolean | 'error' | 'warn' ) => { - if (typeof config === 'object' && config.showSourceLocation === false) { - return original - } if (!stack) { return original } diff --git a/packages/next/src/server/dev/hot-reloader-turbopack.ts b/packages/next/src/server/dev/hot-reloader-turbopack.ts index edcf02d6691fc..e4846cb83ba7f 100644 --- a/packages/next/src/server/dev/hot-reloader-turbopack.ts +++ b/packages/next/src/server/dev/hot-reloader-turbopack.ts @@ -1008,7 +1008,9 @@ export async function createHotReloaderTurbopack( // TODO break case 'browser-logs': { - if (nextConfig.experimental.browserDebugInfoInTerminal) { + const browserToTerminalConfig = + nextConfig.logging && nextConfig.logging.browserToTerminal + if (browserToTerminalConfig) { await receiveBrowserLogsTurbopack({ entries: parsedData.entries, router: parsedData.router, @@ -1016,7 +1018,7 @@ export async function createHotReloaderTurbopack( project, projectPath, distDir, - config: nextConfig.experimental.browserDebugInfoInTerminal, + config: browserToTerminalConfig, }) } break diff --git a/packages/next/src/server/dev/hot-reloader-webpack.ts b/packages/next/src/server/dev/hot-reloader-webpack.ts index bdcd7147c1166..ca78172b42ff6 100644 --- a/packages/next/src/server/dev/hot-reloader-webpack.ts +++ b/packages/next/src/server/dev/hot-reloader-webpack.ts @@ -603,7 +603,9 @@ export default class HotReloaderWebpack implements NextJsHotReloaderInterface { break } case 'browser-logs': { - if (this.config.experimental.browserDebugInfoInTerminal) { + const browserToTerminalConfig = + this.config.logging && this.config.logging.browserToTerminal + if (browserToTerminalConfig) { await receiveBrowserLogsWebpack({ entries: payload.entries, router: payload.router, @@ -613,7 +615,7 @@ export default class HotReloaderWebpack implements NextJsHotReloaderInterface { edgeServerStats: () => this.edgeServerStats, rootDirectory: this.dir, distDir: this.distDir, - config: this.config.experimental.browserDebugInfoInTerminal, + config: browserToTerminalConfig, }) } break diff --git a/test/development/browser-logs/browser-logs.test.ts b/test/development/browser-logs/browser-logs.test.ts index 2784e650c922b..4d25677185376 100644 --- a/test/development/browser-logs/browser-logs.test.ts +++ b/test/development/browser-logs/browser-logs.test.ts @@ -53,13 +53,9 @@ describe(`Terminal Logging (${bundlerName})`, () => { next = await createNext({ files: { pages: new FileRef(join(__dirname, 'fixtures/pages')), - 'next.config.js': ` - module.exports = { - experimental: { - browserDebugInfoInTerminal: true - } - } - `, + 'next.config.js': new FileRef( + join(__dirname, 'fixtures/next.config.js') + ), }, }) }) @@ -162,13 +158,9 @@ describe(`Terminal Logging (${bundlerName})`, () => { next = await createNext({ files: { app: new FileRef(join(__dirname, 'fixtures/app')), - 'next.config.js': ` - module.exports = { - experimental: { - browserDebugInfoInTerminal: true - } - } - `, + 'next.config.js': new FileRef( + join(__dirname, 'fixtures/next.config.js') + ), }, }) }) @@ -226,13 +218,9 @@ describe(`Terminal Logging (${bundlerName})`, () => { next = await createNext({ files: { app: new FileRef(join(__dirname, 'fixtures/app')), - 'next.config.js': ` - module.exports = { - experimental: { - browserDebugInfoInTerminal: true - } - } - `, + 'next.config.js': new FileRef( + join(__dirname, 'fixtures/next.config.js') + ), }, }) }) @@ -292,13 +280,9 @@ describe(`Terminal Logging (${bundlerName})`, () => { next = await createNext({ files: { app: new FileRef(join(__dirname, 'fixtures/app')), - 'next.config.js': ` - module.exports = { - experimental: { - browserDebugInfoInTerminal: true - } - } - `, + 'next.config.js': new FileRef( + join(__dirname, 'fixtures/next.config.js') + ), }, }) }) @@ -326,62 +310,4 @@ describe(`Terminal Logging (${bundlerName})`, () => { await browser.close() }) }) - - describe('Configuration Options', () => { - describe('showSourceLocation disabled', () => { - let next: NextInstance - let logs: string[] = [] - let logCapture: ReturnType - let browser = null - - beforeAll(async () => { - logCapture = setupLogCapture() - logs = logCapture.logs - - next = await createNext({ - files: { - pages: new FileRef(join(__dirname, 'fixtures/pages')), - 'next.config.js': ` - module.exports = { - experimental: { - browserDebugInfoInTerminal: { - showSourceLocation: false - } - } - } - `, - }, - }) - }) - - afterAll(async () => { - logCapture.restore() - await next.destroy() - }) - - beforeEach(() => { - logCapture.clearLogs() - }) - - afterEach(async () => { - if (browser) { - await browser.close() - browser = null - } - }) - - it('should omit source location when disabled', async () => { - browser = await webdriver(next.url, '/basic-logs') - - await browser.waitForElementByCss('#log-button') - await browser.elementByCss('#log-button').click() - - await retry(() => { - const logOutput = logs.join('') - expect(logOutput).toContain('[browser] Hello from browser') - expect(logOutput).not.toMatch(/\([^)]+basic-logs\.[jt]sx?:\d+:\d+\)/) - }) - }) - }) - }) }) diff --git a/test/development/browser-logs/fixtures/next.config.js b/test/development/browser-logs/fixtures/next.config.js new file mode 100644 index 0000000000000..f74baba2bd65b --- /dev/null +++ b/test/development/browser-logs/fixtures/next.config.js @@ -0,0 +1,5 @@ +module.exports = { + logging: { + browserToTerminal: true, + }, +} From 71ac1ec75cfe04785e87e8b8b071cdad9d0d954f Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Thu, 22 Jan 2026 12:38:35 +0100 Subject: [PATCH 4/5] [devtools] Wrap long file names of stack frames in the error overlay (#88886) https://github.com/user-attachments/assets/0594744b-5dd5-4550-90b8-77071962f666 See [overflow-wrap docs](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/overflow-wrap) for break-word vs anywhere. Just a one-line CSS change. The other changes are renaming functions to disambiguate source/codeframe and the filename. --- .../call-stack-frame/call-stack-frame.tsx | 23 ++++++++++--------- .../components/code-frame/code-frame.tsx | 4 ++-- .../components/terminal/terminal.tsx | 4 ++-- .../src/next-devtools/shared/stack-frame.ts | 10 ++++---- .../shared/webpack-module-path.test.ts | 10 ++++---- .../shared/webpack-module-path.ts | 2 +- .../next/src/server/dev/middleware-webpack.ts | 4 ++-- test/lib/next-test-utils.ts | 6 ++--- 8 files changed, 32 insertions(+), 31 deletions(-) diff --git a/packages/next/src/next-devtools/dev-overlay/components/call-stack-frame/call-stack-frame.tsx b/packages/next/src/next-devtools/dev-overlay/components/call-stack-frame/call-stack-frame.tsx index 32f51a3763cd7..855db485e0941 100644 --- a/packages/next/src/next-devtools/dev-overlay/components/call-stack-frame/call-stack-frame.tsx +++ b/packages/next/src/next-devtools/dev-overlay/components/call-stack-frame/call-stack-frame.tsx @@ -2,7 +2,7 @@ import type { OriginalStackFrame } from '../../../shared/stack-frame' import { HotlinkedText } from '../hot-linked-text' import { ExternalIcon, SourceMappingErrorIcon } from '../../icons/external' -import { getFrameSource } from '../../../shared/stack-frame' +import { getStackFrameFile } from '../../../shared/stack-frame' import { useOpenInEditor } from '../../utils/use-open-in-editor' export const CallStackFrame: React.FC<{ @@ -11,9 +11,9 @@ export const CallStackFrame: React.FC<{ // TODO: ability to expand resolved frames const f = frame.originalStackFrame ?? frame.sourceStackFrame - const hasSource = Boolean(frame.originalCodeFrame) + const hasOriginalCodeFrame = Boolean(frame.originalCodeFrame) const open = useOpenInEditor( - hasSource + hasOriginalCodeFrame ? { file: f.file, line1: f.line1 ?? 1, @@ -24,21 +24,21 @@ export const CallStackFrame: React.FC<{ // Formatted file source could be empty. e.g. will be formatted to empty string, // we'll skip rendering the frame in this case. - const fileSource = getFrameSource(f) + const stackFrameFile = getStackFrameFile(f) - if (!fileSource) { + if (!stackFrameFile) { return null } return (
- {hasSource && ( + {hasOriginalCodeFrame && (
) @@ -140,9 +140,10 @@ export const CALL_STACK_FRAME_STYLES = ` } } - .call-stack-frame-file-source { + .call-stack-frame-file { color: var(--color-gray-900); font-size: var(--size-14); line-height: var(--size-20); + word-wrap: break-word; } ` diff --git a/packages/next/src/next-devtools/dev-overlay/components/code-frame/code-frame.tsx b/packages/next/src/next-devtools/dev-overlay/components/code-frame/code-frame.tsx index e23535ab10b48..be8bab972b158 100644 --- a/packages/next/src/next-devtools/dev-overlay/components/code-frame/code-frame.tsx +++ b/packages/next/src/next-devtools/dev-overlay/components/code-frame/code-frame.tsx @@ -1,6 +1,6 @@ import { useMemo } from 'react' import { HotlinkedText } from '../hot-linked-text' -import { getFrameSource, type StackFrame } from '../../../shared/stack-frame' +import { getStackFrameFile, type StackFrame } from '../../../shared/stack-frame' import { useOpenInEditor } from '../../utils/use-open-in-editor' import { ExternalIcon } from '../../icons/external' import { FileIcon } from '../../icons/file' @@ -49,7 +49,7 @@ export function CodeFrame({ stackFrame, codeFrame }: CodeFrameProps) { - {getFrameSource(stackFrame)} @{' '} + {getStackFrameFile(stackFrame)} @{' '}