Skip to content

Turbopack: skip static/media writing for metadata files in dev mode - #89457

Draft
devjiwonchoi wants to merge 1 commit into
canaryfrom
turbopack/skip-static-media-for-metadata-dev
Draft

Turbopack: skip static/media writing for metadata files in dev mode#89457
devjiwonchoi wants to merge 1 commit into
canaryfrom
turbopack/skip-static-media-for-metadata-dev

Conversation

@devjiwonchoi

Copy link
Copy Markdown
Member

Summary

In development mode, static metadata files (favicon.ico, opengraph-image.png, etc.) are now served directly from the app/ directory via the route handler, instead of being written to /_next/static/media/.

This change introduces:

  • A new MetadataStaticImageSource that extracts image metadata (width, height) and computes a content hash for cache-busting, without creating a StaticOutputAsset
  • A new create_metadata_module() method on StructuredImageModuleType for dev-mode metadata handling
  • Pass NextMode through AppPageLoaderTreeBuilder to conditionally use the lightweight module in development

Production builds continue to work as before, writing files to /_next/static/media/.

Test plan

  • pnpm test-dev-turbo test/e2e/app-dir/metadata/metadata.test.ts -t "should render icon" - passes
  • pnpm test-dev-turbo test/e2e/app-dir/metadata/metadata.test.ts -t "should have icons as route" - passes
  • pnpm test-dev-turbo test/e2e/app-dir/metadata/metadata.test.ts -t "should pick up opengraph-image" - passes
  • pnpm test-start-turbo test/e2e/app-dir/metadata/metadata.test.ts -t "should render icon" - passes (production mode still works)

In development mode, static metadata files (favicon.ico, opengraph-image.png,
etc.) are now served directly from the app/ directory via the route handler,
instead of being written to `/_next/static/media/`.

This change introduces a new `MetadataStaticImageSource` that extracts image
metadata (width, height) and computes a content hash for cache-busting, without
creating a `StaticOutputAsset`. Production builds continue to work as before.

Changes:
- Add `MetadataStaticImageSource` for dev-mode metadata image handling
- Add `create_metadata_module()` to `StructuredImageModuleType`
- Pass `NextMode` through `AppPageLoaderTreeBuilder` to conditionally use
  the lightweight module in development
@nextjs-bot nextjs-bot added created-by: Next.js team PRs by the Next.js team. Turbopack Related to Turbopack with Next.js. labels Feb 3, 2026
@codspeed-hq

codspeed-hq Bot commented Feb 3, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 17 untouched benchmarks
⏩ 3 skipped benchmarks1


Comparing turbopack/skip-static-media-for-metadata-dev (c21ff6c) with canary (345a36c)

Open in CodSpeed

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@nextjs-bot

Copy link
Copy Markdown
Contributor

Stats from current PR

🔴 2 regressions, 1 improvement

Metric Canary PR Change Trend
Turbo Build Time 3.942s 4.344s 🔴 +402ms (+10%) ▃▂▁▁▁
Turbo Build Time (cached) 3.992s 4.220s 🔴 +228ms (+6%) ▃▂▁▁▁
node_modules Size 465 MB 462 MB 🟢 2.89 MB (-1%) ▁▁▁▁▁
📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 456ms 455ms ▁▁▁▁▁
Cold (Ready in log) 435ms 437ms ▁▁▂▁▁
Cold (First Request) 1.130s 1.159s ▁▁▅▁▁
Warm (Listen) 456ms 457ms ▁▁▁▁▁
Warm (Ready in log) 439ms 441ms ▁▁▁▁▁
Warm (First Request) 333ms 336ms ▁▂▁▁▁
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 455ms 455ms ▁█▁▁▁
Cold (Ready in log) 435ms 436ms ▆█▅▆▆
Cold (First Request) 1.853s 1.841s ▆█▄▄▅
Warm (Listen) 456ms 456ms ▁█▁▁▁
Warm (Ready in log) 434ms 437ms ▆█▄▅▄
Warm (First Request) 1.865s 1.857s ▅█▃▄▃

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 3.942s 4.344s 🔴 +402ms (+10%) ▃▂▁▁▁
Cached Build 3.992s 4.220s 🔴 +228ms (+6%) ▃▂▁▁▁
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 13.609s 13.911s ▄█▁▁▁
Cached Build 13.832s 14.114s ▄█▁▁▁
node_modules Size 465 MB 462 MB 🟢 2.89 MB (-1%) ▁▁▁▁▁
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles: **437 kB** → **432 kB** ✅ -4.89 kB

81 files with content-based hashes (individual files not comparable between builds)

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 762 B 767 B
Total 762 B 767 B ⚠️ +5 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 450 B 449 B
Total 450 B 449 B ✅ -1 B

📦 Webpack

Client

Main Bundles
Canary PR Change
5528-HASH.js gzip 5.47 kB N/A -
6280-HASH.js gzip 56.8 kB N/A -
6335.HASH.js gzip 169 B N/A -
912-HASH.js gzip 4.53 kB N/A -
e8aec2e4-HASH.js gzip 62.5 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB
main-app-HASH.js gzip 256 B 254 B
main-HASH.js gzip 39 kB 39 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
262-HASH.js gzip N/A 4.52 kB -
2889.HASH.js gzip N/A 169 B -
5602-HASH.js gzip N/A 5.48 kB -
6948ada0-HASH.js gzip N/A 62.3 kB -
9544-HASH.js gzip N/A 53.2 kB -
Total 230 kB 226 kB ✅ -3.92 kB
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 194 B 194 B
_error-HASH.js gzip 183 B 180 B 🟢 3 B (-2%)
css-HASH.js gzip 331 B 330 B
dynamic-HASH.js gzip 1.81 kB 1.81 kB
edge-ssr-HASH.js gzip 256 B 256 B
head-HASH.js gzip 351 B 352 B
hooks-HASH.js gzip 384 B 383 B
image-HASH.js gzip 580 B 581 B
index-HASH.js gzip 260 B 260 B
link-HASH.js gzip 2.49 kB 2.49 kB
routerDirect..HASH.js gzip 320 B 319 B
script-HASH.js gzip 386 B 386 B
withRouter-HASH.js gzip 315 B 315 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.97 kB 7.97 kB ✅ -1 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 126 kB 126 kB
page.js gzip 249 kB 247 kB
Total 375 kB 373 kB ✅ -1.89 kB
Middleware
Canary PR Change
middleware-b..fest.js gzip 615 B 614 B
middleware-r..fest.js gzip 156 B 155 B
middleware.js gzip 33.3 kB 33 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 34.9 kB 34.6 kB ✅ -285 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 732 B 736 B
Total 732 B 736 B ⚠️ +4 B
Build Cache
Canary PR Change
0.pack gzip 3.81 MB 3.72 MB 🟢 96.2 kB (-3%)
index.pack gzip 104 kB 103 kB
index.pack.old gzip 103 kB 101 kB 🟢 1.68 kB (-2%)
Total 4.02 MB 3.92 MB ✅ -98.5 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 312 kB 308 kB 🟢 3.71 kB (-1%)
app-page-exp..prod.js gzip 166 kB 164 kB 🟢 2.02 kB (-1%)
app-page-tur...dev.js gzip 312 kB 308 kB 🟢 3.71 kB (-1%)
app-page-tur..prod.js gzip 166 kB 164 kB 🟢 2.03 kB (-1%)
app-page-tur...dev.js gzip 308 kB 305 kB 🟢 3.63 kB (-1%)
app-page-tur..prod.js gzip 164 kB 162 kB 🟢 2.02 kB (-1%)
app-page.run...dev.js gzip 309 kB 305 kB 🟢 3.64 kB (-1%)
app-page.run..prod.js gzip 164 kB 162 kB 🟢 2.01 kB (-1%)
app-route-ex...dev.js gzip 70.4 kB 70.2 kB
app-route-ex..prod.js gzip 48.9 kB 48.8 kB
app-route-tu...dev.js gzip 70.5 kB 70.2 kB
app-route-tu..prod.js gzip 49 kB 48.8 kB
app-route-tu...dev.js gzip 70.1 kB 69.8 kB
app-route-tu..prod.js gzip 48.7 kB 48.6 kB
app-route.ru...dev.js gzip 70 kB 69.8 kB
app-route.ru..prod.js gzip 48.7 kB 48.6 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 43.2 kB 43.1 kB
pages-api-tu..prod.js gzip 32.9 kB 32.8 kB
pages-api.ru...dev.js gzip 43.1 kB 43.1 kB
pages-api.ru..prod.js gzip 32.8 kB 32.8 kB
pages-turbo....dev.js gzip 52.5 kB 52.4 kB
pages-turbo...prod.js gzip 39.4 kB 39.3 kB
pages.runtim...dev.js gzip 52.4 kB 52.3 kB
pages.runtim..prod.js gzip 39.3 kB 39.3 kB
server.runti..prod.js gzip 62.6 kB 62.5 kB
Total 2.78 MB 2.75 MB ✅ -24.9 kB
📝 Changed Files (25 files)

Files with changes:

  • app-page-exp..ntime.dev.js
  • app-page-exp..time.prod.js
  • app-page-tur..ntime.dev.js
  • app-page-tur..time.prod.js
  • app-page-tur..ntime.dev.js
  • app-page-tur..time.prod.js
  • app-page.runtime.dev.js
  • app-page.runtime.prod.js
  • app-route-ex..ntime.dev.js
  • app-route-ex..time.prod.js
  • app-route-tu..ntime.dev.js
  • app-route-tu..time.prod.js
  • app-route-tu..ntime.dev.js
  • app-route-tu..time.prod.js
  • app-route.runtime.dev.js
  • app-route.ru..time.prod.js
  • pages-api-tu..ntime.dev.js
  • pages-api-tu..time.prod.js
  • pages-api.runtime.dev.js
  • pages-api.ru..time.prod.js
  • ... and 5 more
View diffs
app-page-exp..ntime.dev.js
failed to diff
app-page-exp..time.prod.js
failed to diff
app-page-tur..ntime.dev.js
failed to diff
app-page-tur..time.prod.js
failed to diff
app-page-tur..ntime.dev.js
failed to diff
app-page-tur..time.prod.js
failed to diff
app-page.runtime.dev.js
failed to diff
app-page.runtime.prod.js
failed to diff
app-route-ex..ntime.dev.js

Diff too large to display

app-route-ex..time.prod.js

Diff too large to display

app-route-tu..ntime.dev.js

Diff too large to display

app-route-tu..time.prod.js

Diff too large to display

app-route-tu..ntime.dev.js

Diff too large to display

app-route-tu..time.prod.js

Diff too large to display

app-route.runtime.dev.js

Diff too large to display

app-route.ru..time.prod.js

Diff too large to display

pages-api-tu..ntime.dev.js

Diff too large to display

pages-api-tu..time.prod.js

Diff too large to display

pages-api.runtime.dev.js

Diff too large to display

pages-api.ru..time.prod.js

Diff too large to display

pages-turbo...ntime.dev.js

Diff too large to display

pages-turbo...time.prod.js

Diff too large to display

pages.runtime.dev.js

Diff too large to display

pages.runtime.prod.js

Diff too large to display

server.runtime.prod.js

Diff too large to display

@devjiwonchoi
devjiwonchoi marked this pull request as draft February 14, 2026 21:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

created-by: Next.js team PRs by the Next.js team. Turbopack Related to Turbopack with Next.js.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants