nextjs - ✅(Solved) Fix `default.js` does not trigger sibling `layout.js` [2 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#89920Fetched 2026-04-08 00:21:02
View on GitHub
Comments
2
Participants
2
Timeline
4
Reactions
0
Author
Participants
Timeline (top)
commented ×1cross-referenced ×1issue_type_added ×1labeled ×1

Fix Action

Fixed

PR fix notes

PR #2252: feat: Automatic tree-shaking of messages (experimental)

Description (problem / solution / changelog)

Resolves #1 (but very, very WIP to experiment for now)

TODO

  • Implementation
    • Compiler orchestration
      • Manifest loader only has a single compile pass. Can we do something similar to integrate with extraction loader?
      • Offload more to SWC / Rust? Maybe a single SWC plugin that returns all analysis (useExtracted, deps, 'use client', …)
      • Can we emit extractor and tree shaking result at same time to avoid redundant work?
    • API
      • Should we add a lower-level API? The usage is slightly misleading, because not everything below the provider is collected, but everything that is imported into the module. E.g. import manifest from 'next-intl/client-manifest?path=optional' with {type: 'macro'} would be another candidate, but not sure if the verbosity is worth it (or if it's even clearer). It's surely more explicit, but useExtracted is already implicitly subject to AST transforms—so not sure if we need to do it here.
      • Pages Router?
      • Any way to easily cut off server messages without more work?
    • Edge cases
    • Rework implementation / deslop
    • Performance
  • Tests
    • Can we reuse this for an integration test?
  • First user testing
  • [ ] Docs
    • A playground for toggling layout boundaries?

Changed files

  • e2e/extracted-json/.gitignore (added, +4/-0)
  • e2e/extracted-json/eslint.config.mjs (added, +20/-0)
  • e2e/extracted-json/messages/de.json (added, +4/-0)
  • e2e/extracted-json/messages/en.json (added, +4/-0)
  • e2e/extracted-json/next-env.d.ts (added, +6/-0)
  • e2e/extracted-json/next.config.ts (added, +17/-0)
  • e2e/extracted-json/package.json (added, +37/-0)
  • e2e/extracted-json/playwright.config.ts (added, +18/-0)
  • e2e/extracted-json/src/app/layout.tsx (added, +14/-0)
  • e2e/extracted-json/src/app/page.tsx (added, +14/-0)
  • e2e/extracted-json/src/components/Footer.tsx (added, +8/-0)
  • e2e/extracted-json/src/components/Greeting.tsx (added, +8/-0)
  • e2e/extracted-json/src/i18n/request.ts (added, +9/-0)
  • e2e/extracted-json/tests/helpers.ts (added, +100/-0)
  • e2e/extracted-json/tests/main.spec.ts (added, +335/-0)
  • e2e/extracted-json/tsconfig.json (added, +28/-0)
  • e2e/extracted-po/.gitignore (added, +4/-0)
  • e2e/extracted-po/eslint.config.mjs (added, +20/-0)
  • e2e/extracted-po/messages/en.po (added, +20/-0)
  • e2e/extracted-po/next-env.d.ts (added, +6/-0)
  • e2e/extracted-po/next.config.ts (added, +17/-0)
  • e2e/extracted-po/package.json (added, +37/-0)
  • e2e/extracted-po/playwright.config.ts (added, +18/-0)
  • e2e/extracted-po/src/app/layout.tsx (added, +14/-0)
  • e2e/extracted-po/src/app/page.tsx (added, +14/-0)
  • e2e/extracted-po/src/components/Footer.tsx (added, +8/-0)
  • e2e/extracted-po/src/components/Greeting.tsx (added, +8/-0)
  • e2e/extracted-po/src/i18n/request.ts (added, +9/-0)
  • e2e/extracted-po/tests/helpers.ts (added, +43/-0)
  • e2e/extracted-po/tests/main.spec.ts (added, +507/-0)
  • e2e/extracted-po/tsconfig.json (added, +28/-0)
  • e2e/shared-ui/package.json (added, +15/-0)
  • e2e/shared-ui/src/ProfileCard.tsx (added, +13/-0)
  • e2e/shared-ui/tsconfig.json (added, +11/-0)
  • e2e/tree-shaking/.gitignore (added, +4/-0)
  • e2e/tree-shaking/eslint.config.mjs (added, +16/-0)
  • e2e/tree-shaking/global.ts (added, +11/-0)
  • e2e/tree-shaking/messages/en.po (added, +274/-0)
  • e2e/tree-shaking/messages/manual/en.json (added, +13/-0)
  • e2e/tree-shaking/next-env.d.ts (added, +6/-0)
  • e2e/tree-shaking/next.config.ts (added, +26/-0)
  • e2e/tree-shaking/package.json (added, +42/-0)
  • e2e/tree-shaking/playwright.config.ts (added, +20/-0)
  • e2e/tree-shaking/postcss.config.mjs (added, +7/-0)
  • e2e/tree-shaking/public/favicon.ico (added, +0/-0)
  • e2e/tree-shaking/scripts/check-orphans.mjs (added, +25/-0)
  • e2e/tree-shaking/src/app/(group)/group-one/GroupOneContent.tsx (added, +15/-0)
  • e2e/tree-shaking/src/app/(group)/group-one/page.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/(group)/group-two/GroupTwoContent.tsx (added, +15/-0)
  • e2e/tree-shaking/src/app/(group)/group-two/page.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/(group)/layout.tsx (added, +8/-0)
  • e2e/tree-shaking/src/app/Counter.tsx (added, +26/-0)
  • e2e/tree-shaking/src/app/actions/ActionComponent.tsx (added, +6/-0)
  • e2e/tree-shaking/src/app/actions/ServerActionForm.tsx (added, +24/-0)
  • e2e/tree-shaking/src/app/actions/actions.tsx (added, +14/-0)
  • e2e/tree-shaking/src/app/actions/page.tsx (added, +16/-0)
  • e2e/tree-shaking/src/app/catch-all/[...parts]/CatchAllPageContent.tsx (added, +21/-0)
  • e2e/tree-shaking/src/app/catch-all/[...parts]/page.tsx (added, +18/-0)
  • e2e/tree-shaking/src/app/dynamic-import/DynamicImportContent.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/dynamic-import/DynamicImportPageContent.tsx (added, +18/-0)
  • e2e/tree-shaking/src/app/dynamic-import/LazyImportContent.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/dynamic-import/page.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/dynamic-segment/[slug]/DynamicSlugPageContent.tsx (added, +20/-0)
  • e2e/tree-shaking/src/app/dynamic-segment/[slug]/page.tsx (added, +16/-0)
  • e2e/tree-shaking/src/app/explicit-id/ExplicitIdPageContent.tsx (added, +19/-0)
  • e2e/tree-shaking/src/app/explicit-id/page.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/feed/@modal/(..)photo/[id]/FeedPhotoModalPageContent.tsx (added, +20/-0)
  • e2e/tree-shaking/src/app/feed/@modal/(..)photo/[id]/page.tsx (added, +16/-0)
  • e2e/tree-shaking/src/app/feed/@modal/FeedModalDefaultContent.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/feed/@modal/default.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/feed/FeedPageContent.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/feed/layout.tsx (added, +9/-0)
  • e2e/tree-shaking/src/app/feed/page.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/global-not-found.tsx (added, +17/-0)
  • e2e/tree-shaking/src/app/hook-translation/HookTranslationPageContent.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/hook-translation/page.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/layout-template/LayoutTemplatePageContent.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/layout-template/LayoutTemplateTemplateContent.tsx (added, +19/-0)
  • e2e/tree-shaking/src/app/layout-template/layout.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/layout-template/page.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/layout-template/template.tsx (added, +15/-0)
  • e2e/tree-shaking/src/app/layout.tsx (added, +28/-0)
  • e2e/tree-shaking/src/app/linked-dependency/page.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/loading/LoadingContent.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/loading/loading.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/loading/page.tsx (added, +9/-0)
  • e2e/tree-shaking/src/app/multi-provider/MultiProviderOne.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/multi-provider/MultiProviderOneContent.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/multi-provider/MultiProviderTwo.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/multi-provider/MultiProviderTwoContent.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/multi-provider/page.tsx (added, +11/-0)
  • e2e/tree-shaking/src/app/optional/[[...parts]]/OptionalCatchAllPageContent.tsx (added, +21/-0)
  • e2e/tree-shaking/src/app/optional/[[...parts]]/page.tsx (added, +18/-0)
  • e2e/tree-shaking/src/app/page.tsx (added, +18/-0)
  • e2e/tree-shaking/src/app/parallel/@activity/ParallelActivityDefaultContent.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/parallel/@activity/ParallelActivityPageContent.tsx (added, +13/-0)
  • e2e/tree-shaking/src/app/parallel/@activity/default.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/parallel/@activity/page.tsx (added, +12/-0)
  • e2e/tree-shaking/src/app/parallel/@team/default.tsx (added, +10/-0)
  • e2e/tree-shaking/src/app/parallel/@team/page.tsx (added, +10/-0)

Code Example

src/
└── app
    ├── @slot
    │   ├── default.tsx
    │   └── layout.tsx
    ├── layout.tsx
    └── page.tsx

---

Operating System:
  Platform: darwin
  Arch: x64
  Version: Darwin Kernel Version 25.2.0: Tue Nov 18 21:09:34 PST 2025; root:xnu-12377.61.12~1/RELEASE_X86_64
  Available memory (MB): 16384
  Available CPU cores: 12
Binaries:
  Node: 24.13.0
  npm: 11.6.2
  Yarn: 1.22.22
  pnpm: 10.28.0
Relevant Packages:
  next: 16.2.0-canary.37 // Latest available version is detected (16.2.0-canary.37).
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: N/A
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/amannn/nextjs-bug-repro-default-layout/commit/0470cf213e7ede792d7b75b9167c748885f64df7

To Reproduce

  1. Run app
  2. Open /

Current vs. Expected behavior

Structure:

src/
└── app
    ├── @slot
    │   ├── default.tsx
    │   └── layout.tsx
    ├── layout.tsx
    └── page.tsx

On /, app/@slot/default.tsx renders, but it's not enclosed by app/@slot/layout.tsx.

Based on the available documentation on layouts, I'd expect that they always wrap their sibling entry points within a folder.

If this is not intended, I think it should be documented.

Provide environment information

Operating System:
  Platform: darwin
  Arch: x64
  Version: Darwin Kernel Version 25.2.0: Tue Nov 18 21:09:34 PST 2025; root:xnu-12377.61.12~1/RELEASE_X86_64
  Available memory (MB): 16384
  Available CPU cores: 12
Binaries:
  Node: 24.13.0
  npm: 11.6.2
  Yarn: 1.22.22
  pnpm: 10.28.0
Relevant Packages:
  next: 16.2.0-canary.37 // Latest available version is detected (16.2.0-canary.37).
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Parallel & Intercepting Routes

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

No response

extent analysis

Problem Summary

Layout Issue with Next.js

Root Cause Analysis

Layout not wrapping sibling entry points

Fix Plan

Step 1: Update next.config.js

module.exports = {
  // ...
  experimental: {
    appDir: true,
  },
};

Step 2: Update app/@slot/layout.tsx

import { SlotLayout } from 'next';

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <SlotLayout>
      {children}
    </SlotLayout>
  );
}

Step 3: Update app/@slot/default.tsx

import { SlotLayout } from 'next';

export default function Default() {
  return (
    <div>
      <h1>Default Layout</h1>
    </div>
  );
}

Step 4: Run npm run dev or yarn dev to rebuild and restart the development server

Verification

  1. Open / in your browser.
  2. Verify that app/@slot/layout.tsx is rendering around app/@slot/default.tsx.

Extra Tips

  • Make sure to update next.config.js to include experimental.appDir: true to enable the new app directory feature.
  • Use the SlotLayout component from next to wrap your layout components.
  • Run npm run build or yarn build to rebuild the production code.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

nextjs - ✅(Solved) Fix `default.js` does not trigger sibling `layout.js` [2 pull requests, 2 comments, 2 participants]