Niklas Mischkulnig
90d · built 2026-09-30
Performance
What Niklas Mischkulnig shipped in the selected window, measured in ETV, and how it compares with the 90 days before it.
Effective capacity
+0.8engineers
delivers like 1.8 (1.8x pre-AI)
Output (ETV)
21.4ETV
+22.6% vs 17.5 prior
Features share
25.6%
+0.6 pp vs prior window
Fixes share
20.6%
+14.2 pp vs prior window
Work mix
25.6% Features19.6% Maintenance32.4% Tests1.8% Docs20.6% Fixes
106 commits over 90 days, ending 2026-09-30.
Where this dev ranks
Percentile against the global top-100 leaderboard (all-time totals).
- By commits
- Top 40 %
- By Features share
- Top 89 %
Daily performance
Daily ETV, stacked by Features, Maintenance, Tests, Docs and Fixes.
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
Most impactful commits
Top 10 by ETV in the last 90 days.
- 2.7ETVTurbopack: emit/collect (#96631) Only add this for using it for Server Actions for now Undocumented, not API stable. But we can't really put it behind a flag, because the next-custom-transform is going to add it New traits: ```rust /// A module that can collect other modules during the collect phase. #[turbo_tasks::value_trait] pub trait CollectingModule: Module { /// The namespace that this module is interesed in #[turbo_tasks::function] fn namespace(self: Vc<Self>) -> Vc<RcStr>; #[turbo_tasks::function] fn as_chunk_item( self: Vc<Self>, module_graph: Vc<ModuleGraph>, chunking_context: Vc<Box<dyn ChunkingContext>>, entry_chunk_group: Vc<Modules>, ) -> Vc<Box<dyn ChunkItem>>; } #[turbo_tasks::value_trait] pub trait EmittedModuleReference: ModuleReference + ValueToString { #[turbo_tasks::function] fn data(self: Vc<Self>) -> Vc<CompileTimeDefineValue>; } ``` Example: ```javascript __turbopack_emit__('./c.js', { namespace: 'my-test', data: 'data-for-c', // optional exports: ['c'], // optional with: ... // optional, import attributes like with ESM }) // ------------------------- const getList = __turbopack_collect__({ namespace: 'my-test', }) const list = getList(); ``` Shortcomings in the current version (which are not a blocker for now however): - data-only emit not implemented - stylegroups aren't properly implemented. emitting styles is probably broken - pages router is still a problem: it has two separate ChunkGroup::Entry, so you only see what was emitted on the current runtime, not both Recreation of https://github.com/vercel/next.js/pull/91100github.com-vercel-next.js · 66170577 · 2026-08-24
- 1.9ETVTurbopack: cross-module constants (#90300) Closes https://github.com/vercel/next.js/issues/92082 This is now a proper compile-time constant: ```js import { IS_DEV } from './other' if (IS_DEV) { // statically evaluates to `true` console.log('x') } else { require("library") // not bundled } console.log(IS_DEV); // is replaced with console.log(true); ``` ```typescript // other.ts export const SOME_VALUE = 'x' const node_env = process.env.NODE_ENV const development_ent = 'development' export const IS_DEV = node_env === development_ent ``` You can use code to compute constants just fine, and use any existing constants such as `process.env.NODE_ENV`. Currently, you can't use imports to other constants modules, but we can add that later on. We can't perform this constants check for every single import, so you need to either - have `UPPER_CASE` import names as in the example above - or use `import { lower } from './other' with { turbopackConstants: 'true' }` Then that referenced module will be analyzed for constants, and if the referenced export is a constant, it will participate in constant inlining just as `process.env.FOO`. This also works fine with barrel imports, you can still do `import { IS_DEV } from './barrel.js'` and it will find the `constants.js` file which in itself will indeed only have constants exports. Because it's not always opt-in at the import site, we can't automatically make non-constant exports an error. For that you have to add `'use turbopack: constants'` at the top of the module, which will make it an error if any constant import references that module, and the module has any non-constant exports: ``` error - [analysis] /turbopack/crates/turbopack-tests/tests/snapshot/comptime/cross-module/input/other.constants.js:8:7 Export NO_CONSTANT is not a constant 4 | const development_ent = 'development' 5 | 6 | export const IS_DEV = node_env === development_ent 7 | + v--------------------------------v 8 + export const NO_CONSTANT = globalThis.foo + ^--------------------------------^ 9 | It was analyzed to be FreeVar(globalThis)["foo"] Import trace: test: ./turbopack/crates/turbopack-tests/tests/snapshot/comptime/cross-module/input/other.constants.js ./turbopack/crates/turbopack-tests/tests/snapshot/comptime/cross-module/input/index.js ``` Some prior art: https://rspack.rs/blog/announcing-1-5#const-inline-optimization, https://rspack.rs/config/optimization#optimizationinlineexports No compile-time impact on a big app: ``` canary dfbc3dc6b7: 438.11s user, 68.35s system, 801% cpu, 1:03.22 total 439.44s user, 71.47s system, 756% cpu, 1:07.56 total 440.32s user, 68.57s system, 750% cpu, 1:07.81 total constants 2d7eb8220d298133212813b7267a5847eed03a22 433.22s user, 65.44s system, 800% cpu, 1:02.32 total 440.52s user, 67.68s system, 770% cpu, 1:05.95 total 433.13s user, 69.47s system, 776% cpu, 1:04.74 total ``` a8620556af64ef550373cca1e1fc701a1a8583ccgithub.com-vercel-next.js · 606c4ebb · 2026-08-19
- 1.4ETVtest: run cargo unit tests with miri as well (#97535) ### What? Adds a CI job that runs selected Rust unit tests under [Miri](https://github.com/rust-lang/miri) to detect undefined behavior in unsafe code. The job currently covers the low-level crates that are compatible with Miri: - `turbo-persistence` - `turbo-rcstr` - `turbo-tasks-malloc` It also makes those crates Miri-compatible by: - using provenance-free tagged-pointer operations in `turbo-rcstr`; - disabling mimalloc and native compression under Miri; - making mmap support a default-enabled Cargo feature that is disabled for Miri and wasm; - running persistence through file I/O when mmap is disabled; - skipping only tests measured to exceed the Miri time budget; - removing leaked test arenas from the analyzer predicate tests. ### Why? Miri can detect invalid memory access and other undefined behavior that normal Rust tests may not expose. Running it in CI gives low-level unsafe code an additional correctness check. The job uses an explicit package allowlist because Turbo Tasks builds its generated registry from linker sections, and Miri does not support the linker-defined section symbols required by that registry. ### How? - Installs the `miri` Rust component in CI and the development container. - Adds a dedicated `test-cargo-unit-miri` task and reusable workflow configuration. - Makes `memmap2` optional behind the default `mmap` feature and disables that feature in Miri CI and the wasm dependency graph. - Uses structural `cfg(miri)` branches for allocator and compression paths Miri cannot execute. - Re-enables three persistence compaction tests after measuring them successfully under Miri. - Keeps normal native behavior unchanged and documents measured Miri exclusions at the affected tests. Verification included focused normal and Miri tests for persistence, rcstr, allocation accounting, compression, and the refactored leak-free predicate cases. <!-- NEXT_JS_LLM --> <!-- fleet fb42942f-173a-484c-b4de-4e18354834c6 --> --------- Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com> Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>github.com-vercel-next.js · 3bf71ee3 · 2026-09-18
- 1.0ETVMore granular cache keys for use-cache entries (#95233) Caveats: - I had to skip `react[-dom][/*]` and `private-next-rsc-server-reference` and `private-next-rsc-cache-wrapper` imports in the code hash and env-var tracking. Because those all end up pulling in app-page-turbo.runtime.prod.js which reads many env vars and would cause constant deopting. But this should still be correct. The code of these imports is included via the Next.js version, and no env vars should change the semantics of any of those imports. - Static env var reads are collected, but too dynamic accesses are silently ignored and don't lead to deopts (same goes for env var reads in native NAPI addons). This means that this cache reuse is not guaranteed to be 100% guaranteed to never lead to stale caches. - Code hashing and env var collection happens on a per-module basis. So if you put all use-cache functions into a single file and/or together with react components, then you will see extraneous invalidations. This will be fixed by either generally enabling module splitting for all of Turbopack, or by adding a special transform that does it for use-cache functions. Followups: - There are some env var static analysis gaps that will be immediate followups before broader testing. These are the various TODOs added in https://github.com/vercel/next.js/pull/95310 - Client components invalidation is very coarse grained right now (statically imports any client component anywhere -> deopt completely). Followup for the future. But the current setup is correct. This would just improve effectiveness further - Do this in dev as well. Currently there is no NFT at all in dev (for performance reasons) - Module splitting for more granular tracking - Include entropy when serializing server reference arguments for cache key Todo: - [x] Use implementation code hash (includes inlined env vars): from #94234 - [x] Include non-inlined runtime env vars: from #95310 - [x] Include client reference manifest (very coarse for now) - [x] Include Next.js version (for wire format, etc) - [x] This is now done for all use-cache entries now. Not just for `use cache: remote`. Is that the intended behavior? Yes - [ ] ~~if `NEXT_DEPLOYMENT_ID` is in the env vars. just deopt and don't care about stringifing and hashing the env vars~~ - [x] Is cache key size a problem? Currently you can get this: (values are always hashed) `CustomCacheHandler::get ["80e6f6560092f0078775e7e787c1c10ecf6dea0bc4",[],["d984fbaa996274737f3b59345a300a20","16.4.0-canary.5","__NEXT_NO_MIDDLEWARE_URL_NORMALIZE=undefined","NEXT_OTEL_PERFORMANCE_PREFIX=undefined","__NEXT_PRIVATE_ORIGIN=a04f4b9d6a8f42724740a480e9a2bc67c053dc04377be831c0e2c407a1422004","NEXT_PRIVATE_RESPONSE_CACHE_TTL=undefined","NEXT_PRIVATE_RESPONSE_CACHE_MAX_SIZE=undefined","__NEXT_CACHE_COMPONENTS=b5bea41b6c623f7c09f1bf24dcae58ebab3c0cdd90ad966bc43a45b44867e12b","__NEXT_ROUTER_BASEPATH=undefined","__NEXT_MANUAL_CLIENT_BASE_PATH=undefined","__NEXT_INSTRUMENTATION_CLIENT_ROUTER_TRANSITION_EVENTS=undefined","__NEXT_APP_NAV_FAIL_HANDLING=undefined","__NEXT_GESTURE_TRANSITION=undefined","__NEXT_USE_OFFLINE=undefined","NEXT_DEBUG_BUILD=undefined","__NEXT_VERBOSE_LOGGING=undefined...]] [["_N_T_/layout","_N_T_/page","_N_T_/","_N_T_/index"]]`github.com-vercel-next.js · e3790aa9 · 2026-08-28
- 0.9ETVTurbopack: expose list of non-inlined env vars (#95310) Add a new method to `EcmascriptAnalyzable` to return the list of non-inlined env vars In this PR, this isn't used anywhere outside of the tests yet While `cargo bench -p turbopack-ecmascript` does regress: ``` Benchmarking references/packages-bundle.js/full: Warming up for 1.0000 s references/packages-bundle.js/full time: [152.99 ms 153.34 ms 153.70 ms] change: [+11.939% +12.678% +13.307%] (p = 0.00 < 0.05) Performance has regressed. Found 4 outliers among 100 measurements (4.00%) 4 (4.00%) high mild Benchmarking references/packages-bundle.js/tracing: Warming up for 1.0000 s references/packages-bundle.js/tracing time: [153.07 ms 153.92 ms 155.15 ms] change: [+34.997% +36.345% +37.554%] (p = 0.00 < 0.05) Performance has regressed. Found 4 outliers among 100 measurements (4.00%) 2 (2.00%) high mild 2 (2.00%) high severe ``` There is no measurable overall perf impact: ``` commit 7d29e358c8ac383a3019d552fd54f4d05645bf39 (HEAD, tag: v16.4.0-canary.5) v16.4.0-canary.5 pnpm next build --experimental-build-mode=compil 400.89s user 51.96s system 747% cpu 1:00.61 total pnpm next build --experimental-build-mode=compil 394.99s user 54.10s system 757% cpu 59.289 total pnpm next build --experimental-build-mode=compil 399.87s user 58.71s system 772% cpu 59.398 total ``` vs ``` commit 9335597135118b8332b8e0d5a3bcedb596a3ef07 (HEAD -> mischnic/env-var-references) remove runtime_all pnpm next build --experimental-build-mode=compil 399.83s user 50.09s system 719% cpu 1:02.57 total pnpm next build --experimental-build-mode=compil 403.57s user 53.79s system 743% cpu 1:01.52 total pnpm next build --experimental-build-mode=compil 402.23s user 55.05s system 758% cpu 1:00.29 total pnpm next build --experimental-build-mode=compil 400.17s user 55.15s system 761% cpu 59.817 total ```github.com-vercel-next.js · d09816fd · 2026-08-26
- 0.7ETVFix startTime and shutdown delivery of forwarded Turbopack trace spans (#98426) before: <img width="1358" height="313" alt="Bildschirmfoto 2026-09-09 um 14 33 59" src="https://github.com/user-attachments/assets/69c2dc9c-06f1-4df1-b5eb-e6878f2abe32" /> after: <img width="1273" height="207" alt="Bildschirmfoto 2026-09-09 um 16 32 57" src="https://github.com/user-attachments/assets/a601e1c6-c0b8-425f-b977-b58d92289ab6" /> ## Summary Two fixes for Turbopack compilation events forwarded to the JS trace (`.next/trace`). The span-forwarding work stacks on top of this PR. - **`Span.manualTraceChild` serialized the event recording time as `startTime`** instead of the supplied epoch start, so forwarded spans rendered shifted forward by their own duration and overflowed their parent span. `startTime` now reflects the supplied start. - **Compilation events were lost at build shutdown**: `CompilationEventQueue` delivered events via an untracked `tokio::spawn`, and the build teardown aborted the events subscription right after `project.shutdown()` resolved, so shutdown-time events (e.g. `turbopack-persistence` on cold builds, where it is the only persistence event since builds use `ReadWriteOnShutdown`) were discarded whenever delivery lost the race. The queue now tracks in-flight deliveries and flushes/closes subscriber channels at the end of `stop_and_wait`, and the build waits for the subscription to drain before aborting it. ## Verification - New `trace.test.ts` unit test: a `manualTraceChild` span started in the past keeps its own start time (fails before the fix, passes after). - New `message_queue::test_flush_and_close` unit test: events are delivered before the channel closes; post-close subscriptions replay history and close. - `cargo check` / `cargo test -p turbo-tasks --lib message_queue`, root `pnpm typescript`. - The stacked PR on top verifies end-to-end that `turbopack-persistence` is now emitted on every cold build. <!-- NEXT_JS_LLM --> <!-- fleet 107de4c7-6206-422b-a422-9cc8d7047774 --> --------- Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com>github.com-vercel-next.js · 719d7cea · 2026-09-22
- 0.7ETVBump swc to v77 (#97407) There have been breaking changes to the AST: - `BlockStmtOrExpr` is now `ArrowFunctionBody` - function bodies are `FunctionBody` instead of `BlockStmt` - JSX text literals are `Wtf8Atom`, instead of `Atom`github.com-vercel-next.js · 538f3f68 · 2026-09-02
- 0.7ETVDurable use cache: optimize env var existence checks (#98504) We now separately track code that accesses non-inlined env vars at runtime in two categories - (existing) actual reads, the full value is accessed - (new) only unset/falsy/truthy is read at runtime For the second case, we only need to invalidate use-cache functions when the given env var transitioned betwen unset/falsy/truthy. But transitioning between two different truthy values doesn't caused invalidation.github.com-vercel-next.js · f41441a0 · 2026-09-11
- 0.6ETVChange `loadManifest` to return undefined with `handleMissing` (#96530) Previously, this returned `{} as T` which was unsafe. Now it properly returns `undefined` instead and the caller can decide what the fallback value should begithub.com-vercel-next.js · ab09c1f4 · 2026-08-05
- 0.6ETVRespect NEXT_HASH_SALT for server side assetsHashes (#95738) Also respect the hash salt for `assetsHashes`github.com-vercel-next.js · b3480cfd · 2026-07-15