The public barrel pulls node:crypto in eagerly through the session-encryption code, so importing the router initialises the optional native subsystem in every application, including the great majority that never open an encrypted session.
Chunk graph at v0.1.15, from the published dist:
index.js -> chunk-7s1kcj7w.js -> chunk-9y37n6xs.jsand chunk-9y37n6xs.js opens with three of these:
import{createCipheriv as On,createDecipheriv as Rn,randomBytes as st}from"crypto"src/crypto.ts already has the pattern this wants - getNodeCrypto(), resolved on first use and cached - and auth.ts and middleware/csrf.ts use it for timingSafeEqual. The session-encryption module is the remaining static importer.
Why it is worth doing
It is the last thing standing between the router and a crypto-free import. stacksjs/stacks#2450 removed the equivalent static import from its own signed-URL helper and measured no improvement, because this one loads the subsystem regardless. Fresh process, isolated benchmark config, Bun 1.3.14 / macOS arm64, 7 runs each:
| wall | RSS | |
|---|---|---|
| empty process | 12.2 ms | 22.0 MB |
import 'node:crypto' alone | 16.4 ms | 27.4 MB |
| Stacks router barrel on bun-router 0.1.15 | 33.6 ms | 43.6 MB |
Direction-only startup diagnostics on a developer machine, not throughput or settled-memory claims, and RSS deltas can include shared native initialisation - so they need measuring again after the change rather than subtracting arithmetically.
What would close it
- Session encryption resolves
createCipheriv/createDecipheriv/randomBytesthroughgetNodeCrypto()rather than a static import, caching the module as that helper already does. cryptois absent from the transitive chunk graph ofindex.jsin the built output, asserted by a test over the dist rather than the source, since the source graph is not what ships.- Same primitives, same synchronous APIs, same exports; cold and warm encrypt/decrypt behaviour unchanged.
- Fresh-process baseline and candidate measured, both reported, including if the win does not appear.