vercel / vercel/next.js

Turbopack dev: a route handler compiled after N pages costs ~16 MB × N (50 pages + 34 handlers → 29 GB); regressed in 16.3.0-canary.101

Open
#98,707 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Performance Route Handlers Turbopack
Dominant language
JavaScript
Stars
142k
Forks
32.4k
Avg merge
2d 14h
Merged PRs (30d)
351

Description

Link to the code that reproduces this issue

https://github.com/danielcizin/next-16-3-route-handler-memory-repro

To Reproduce
  1. npm install && node gen.mjs (writes 50 trivial app/p*/page.tsx and 34 trivial app/api/h*/route.ts; TypeScript 5 is pinned).
  2. node drive.mjs pages-first — fresh .next, starts next dev, GETs every page, then GETs every route handler, printing the dev server's RSS (the process listening on the port) every 10 routes.
  3. node drive.mjs handlers-first — the same with the handlers requested before the pages.
Current vs. Expected behavior

Current (next@16.3.4, also 16.3.5): after the 50 pages are compiled (~11 MB each, RSS 1.1 GB), each route handler compiled afterwards adds ~820 MB — RSS goes 1.1 → 9.2 → 17.4 → 25.7 → 29.0 GB across the 34 handlers, in 2.9 s. Requested before the pages, the same 34 handlers add ~9 MB each and the whole run ends at 1.4 GB.

The per-handler cost is linear in the number of pages already compiled: 10 pages → ~170 MB per handler, 25 → ~410 MB, 50 → ~820 MB. Removing the one shared import from the handlers (HANDLER_IMPORT=0) or from the pages (PAGE_IMPORT=0) changes nothing (28.9 GB / 27.2 GB).

Expected: a route handler's compile cost independent of how many pages were compiled before it, as in 16.2.6, where the same pages-first run ends at 2.1 GB (handlers ~9 MB each).

Bisected in the same harness (PAGES=10 HANDLERS=34, pages first; good ≈ 1 GB, bad ≈ 6.3 GB): 16.2.6, 16.3.0-canary.0/.53/.80/.93/.96/.99/.100 good; 16.3.0-canary.101 bad; 16.3.0 bad. That canary's release notes are four Turbopack server-HMR changes: #95546, #95795, #95661, #94948.

Where it bit: a CI browser matrix whose warmup requests 52 pages and then 33 route handlers of a real app killed 7 GB and 16 GB GitHub-hosted runners the moment the handlers were requested (dev server 5.9 → 8.9 → 11.7 → 14.3 GB across three handlers); reordering the warmup to handlers-first restored a 1.4 GB run. None of experimental.turbopackMemoryEviction: 'full', turbopackFileSystemCacheForDev: false, turbopackSourceMaps: false, or devMemoryThresholdRestart: false changed the peak.

Provide environment information
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050
  Available memory (MB): 131072
  Available CPU cores: 18
Binaries:
  Node: 26.0.0
  npm: 11.16.0
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 16.3.4
  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)

Turbopack, Route Handlers, Performance

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

next dev (local)

Additional context

Full measurement tables (both orders, three versions, the scaling series, and the bisect) are in the reproduction's README. Measured on macOS arm64 with 128 GB RAM so the run completes; on smaller machines the process is killed once the handlers start compiling. turbopackMemoryLimit (accepted by the 16.2 binding) is no longer present in 16.3's binding, so there is no bound to fall back on.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked reproduction, especially gen.mjs and drive.mjs, and run the pages-first and handlers-first next dev cases to confirm the memory growth. Compare the bisected boundary at 16.3.0-canary.101 with 16.2.6 and inspect the four listed Turbopack server-HMR changes (#95546, #95795, #95661, #94948). Done means route-handler compile cost no longer scales with previously compiled pages and the pages-first run has comparable memory to handlers-first.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, nextjs, react, typescript
Domain
build-system, performance
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.