diff --git a/packages/next/src/server/app-render/create-component-tree.tsx b/packages/next/src/server/app-render/create-component-tree.tsx
index 209c237b5e047..e28dfeda953dd 100644
--- a/packages/next/src/server/app-render/create-component-tree.tsx
+++ b/packages/next/src/server/app-render/create-component-tree.tsx
@@ -21,7 +21,6 @@ import type { LoadingModuleData } from '../../shared/lib/app-router-context.shar
import type { Params } from '../request/params'
import { workUnitAsyncStorage } from './work-unit-async-storage.external'
import { OUTLET_BOUNDARY_NAME } from '../../lib/metadata/metadata-constants'
-import { DEFAULT_SEGMENT_KEY } from '../../shared/lib/segment'
import type { UseCachePageComponentProps } from '../use-cache/use-cache-wrapper'
/**
@@ -394,19 +393,12 @@ async function createComponentTreeInternal({
// Resolve the segment param
const actualSegment = segmentParam ? segmentParam.treeSegment : segment
-
- // Only render metadata on the actual SSR'd segment not the `default` segment,
- // as it's used as a placeholder for navigation.
- const isNotDefaultSegment = actualSegment !== DEFAULT_SEGMENT_KEY
-
- const metadata =
- isNotDefaultSegment && StreamingMetadata ? : undefined
+ const metadata = StreamingMetadata ? : undefined
// Use the same condition to render metadataOutlet as metadata
- const metadataOutlet =
- isNotDefaultSegment && StreamingMetadataOutlet ? (
-
- ) : undefined
+ const metadataOutlet = StreamingMetadataOutlet ? (
+
+ ) : undefined
const notFoundElement = NotFound ? (
<>
diff --git a/test/e2e/app-dir/metadata-streaming/app/dynamic-api/page.tsx b/test/e2e/app-dir/metadata-streaming/app/dynamic-api/page.tsx
index 6a521e8de1f33..af601aced5059 100644
--- a/test/e2e/app-dir/metadata-streaming/app/dynamic-api/page.tsx
+++ b/test/e2e/app-dir/metadata-streaming/app/dynamic-api/page.tsx
@@ -23,7 +23,7 @@ async function SubComponent() {
export async function generateMetadata() {
await connection()
- await new Promise((resolve) => setTimeout(resolve, 3000))
+ await new Promise((resolve) => setTimeout(resolve, 800))
return {
title: `Dynamic api ${Math.random()}`,
}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/default.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/default.tsx
new file mode 100644
index 0000000000000..e355998a4433c
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/default.tsx
@@ -0,0 +1,3 @@
+export default function Page() {
+ return 'default @bar'
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/layout.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/layout.tsx
new file mode 100644
index 0000000000000..1e18e748cf81e
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/layout.tsx
@@ -0,0 +1,8 @@
+export default function Layout({ children }) {
+ return (
+
+
@bar Layout
+
{children}
+
+ )
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/page.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/page.tsx
new file mode 100644
index 0000000000000..eb4a3e2e9df71
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/page.tsx
@@ -0,0 +1,3 @@
+export default function Page() {
+ return 'page @bar'
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/test-page/page.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/test-page/page.tsx
new file mode 100644
index 0000000000000..bff087a3a98f9
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@bar/test-page/page.tsx
@@ -0,0 +1,3 @@
+export default function Page() {
+ return 'test-page @bar'
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/default.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/default.tsx
new file mode 100644
index 0000000000000..408576f1876b5
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/default.tsx
@@ -0,0 +1,3 @@
+export default function Page() {
+ return 'default @foo'
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/layout.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/layout.tsx
new file mode 100644
index 0000000000000..05a3bda4f7be8
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/layout.tsx
@@ -0,0 +1,8 @@
+export default function Layout({ children }) {
+ return (
+
+
@foo Layout
+
{children}
+
+ )
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/no-bar/page.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/no-bar/page.tsx
new file mode 100644
index 0000000000000..44ab40e2ddfce
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/no-bar/page.tsx
@@ -0,0 +1,3 @@
+export default function Page() {
+ return 'no-bar @foo'
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/page.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/page.tsx
new file mode 100644
index 0000000000000..3536981cea3ff
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/page.tsx
@@ -0,0 +1,3 @@
+export default function Page() {
+ return 'page @foo'
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/test-page/page.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/test-page/page.tsx
new file mode 100644
index 0000000000000..8eff01dbe6dec
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/@foo/test-page/page.tsx
@@ -0,0 +1,3 @@
+export default function Page() {
+ return 'test-page @foo'
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/default.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/default.tsx
new file mode 100644
index 0000000000000..2b713383cfcdb
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/default.tsx
@@ -0,0 +1,3 @@
+export default function Page() {
+ return 'default no-children'
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/layout.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/layout.tsx
new file mode 100644
index 0000000000000..907190e027c57
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/layout.tsx
@@ -0,0 +1,22 @@
+import { connection } from 'next/server'
+
+export default function Layout({ bar, foo, children }) {
+ return (
+
+
Parallel Routes Layout - No Children
+
{foo}
+
{bar}
+
+ {/* hitting default.js */}
+ {children}
+
+ )
+}
+
+export async function generateMetadata() {
+ await connection()
+ await new Promise((resolve) => setTimeout(resolve, 300))
+ return {
+ title: 'parallel-routes-default layout title',
+ }
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/no-bar/page.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/no-bar/page.tsx
new file mode 100644
index 0000000000000..640e2e61603f7
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/no-bar/page.tsx
@@ -0,0 +1,13 @@
+import { connection } from 'next/server'
+
+export default function TestPage() {
+ return 'test page'
+}
+
+export async function generateMetadata() {
+ await connection()
+ await new Promise((resolve) => setTimeout(resolve, 3000))
+ return {
+ title: `Dynamic api ${Math.random()}`,
+ }
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/test-page/page.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/test-page/page.tsx
new file mode 100644
index 0000000000000..4fee1a94819fb
--- /dev/null
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes-default/test-page/page.tsx
@@ -0,0 +1,13 @@
+import { connection } from 'next/server'
+
+export default function TestPage() {
+ return 'test page'
+}
+
+export async function generateMetadata() {
+ await connection()
+ await new Promise((resolve) => setTimeout(resolve, 1000))
+ return {
+ title: `Dynamic api ${Math.random()}`,
+ }
+}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes/no-bar/page.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes/no-bar/page.tsx
index 640e2e61603f7..773d8bbaa1719 100644
--- a/test/e2e/app-dir/metadata-streaming/app/parallel-routes/no-bar/page.tsx
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes/no-bar/page.tsx
@@ -1,13 +1,20 @@
+import Link from 'next/link'
import { connection } from 'next/server'
-export default function TestPage() {
- return 'test page'
+export default function Page() {
+ return (
+
+
no bar
+
Back to /parallel-routes
+
+ )
}
export async function generateMetadata() {
await connection()
- await new Promise((resolve) => setTimeout(resolve, 3000))
+ await new Promise((resolve) => setTimeout(resolve, 1000))
return {
title: `Dynamic api ${Math.random()}`,
+ description: 'no-bar description',
}
}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes/page.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes/page.tsx
index 5739a4c02e37b..4ce809e3634d1 100644
--- a/test/e2e/app-dir/metadata-streaming/app/parallel-routes/page.tsx
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes/page.tsx
@@ -3,10 +3,11 @@ import Link from 'next/link'
export default function Page() {
return (
- Hello from Nested{' '}
+ Hello from Nested
To /parallel-routes/test-page
+
To /parallel-routes/no-bar
)
@@ -14,4 +15,5 @@ export default function Page() {
export const metadata = {
title: 'parallel title',
+ description: 'parallel description',
}
diff --git a/test/e2e/app-dir/metadata-streaming/app/parallel-routes/test-page/page.tsx b/test/e2e/app-dir/metadata-streaming/app/parallel-routes/test-page/page.tsx
index 640e2e61603f7..4fee1a94819fb 100644
--- a/test/e2e/app-dir/metadata-streaming/app/parallel-routes/test-page/page.tsx
+++ b/test/e2e/app-dir/metadata-streaming/app/parallel-routes/test-page/page.tsx
@@ -6,7 +6,7 @@ export default function TestPage() {
export async function generateMetadata() {
await connection()
- await new Promise((resolve) => setTimeout(resolve, 3000))
+ await new Promise((resolve) => setTimeout(resolve, 1000))
return {
title: `Dynamic api ${Math.random()}`,
}
diff --git a/test/e2e/app-dir/metadata-streaming/metadata-streaming.test.ts b/test/e2e/app-dir/metadata-streaming/metadata-streaming.test.ts
index eae22f99affe4..121df695128ae 100644
--- a/test/e2e/app-dir/metadata-streaming/metadata-streaming.test.ts
+++ b/test/e2e/app-dir/metadata-streaming/metadata-streaming.test.ts
@@ -93,9 +93,11 @@ describe('app-dir - metadata-streaming', () => {
expect((await browser.elementsByCss('head title')).length).toBe(1)
expect((await browser.elementsByCss('body title')).length).toBe(0)
+ expect(await browser.elementByCss('title').text()).toBe('parallel title')
const $ = await next.render$('/parallel-routes')
expect($('title').length).toBe(1)
+ expect($('head title').text()).toBe('parallel title')
// validate behavior remains the same on client navigations
await browser.elementByCss('[href="/parallel-routes/test-page"]').click()
@@ -113,13 +115,29 @@ describe('app-dir - metadata-streaming', () => {
const browser = await next.browser('/parallel-routes')
await browser.elementByCss('[href="/parallel-routes/no-bar"]').click()
+ // Wait for navigation is finished and metadata is updated
await retry(async () => {
expect(await browser.elementByCss('title').text()).toContain(
'Dynamic api'
)
})
+ await retry(async () => {
+ expect((await browser.elementsByCss('title')).length).toBe(1)
+ })
+ })
+
+ it('should still render metadata if children is not rendered in parallel routes layout', async () => {
+ const browser = await next.browser('/parallel-routes-default')
+
expect((await browser.elementsByCss('title')).length).toBe(1)
+ expect(await browser.elementByCss('body title').text()).toBe(
+ 'parallel-routes-default layout title'
+ )
+
+ const $ = await next.render$('/parallel-routes-default')
+ expect($('title').length).toBe(1)
+ expect($('body title').text()).toBe('parallel-routes-default layout title')
})
describe('dynamic api', () => {