Node.js 14: Diagnostic Reports and Internationalization
Node.js 14 lands April 21. I’ve been poking at the dev branch for a few weeks now, and two things keep standing out: Diagnostic Reports graduating to stable, and full ICU internationalization data shipping by default.
Neither is glamorous. Both are the kind of thing that makes Node.js meaningfully better in production — which is exactly what I care about.
Diagnostic Reports Go Stable #
Diagnostic Reports have been experimental since Node.js 11. The concept is straightforward: when something goes wrong (a crash, a hang, a weird performance cliff you can’t explain), you generate a JSON report that captures the full state of the process. Stack traces, heap statistics, resource usage, libuv handle information, environment variables, loaded native modules. Everything you’d want in a post-mortem.
In v14, this graduates from experimental to stable. That matters for one reason: the API is frozen. You can actually depend on it in production tooling now without worrying it’ll shift under you.
Here’s the basic API. You can trigger a report programmatically:
const report = process.report.getReport();
console.log(report.header.nodeVersion);
console.log(report.libuv); // open handles, requests
Or tie it to specific signals:
process.report.reportOnSignal = true;
process.report.signal = 'SIGUSR2';Or — and this is the one I think most teams will actually care about — on uncaught exceptions and fatal errors:
process.report.reportOnFatalError = true;
process.report.reportOnUncaughtException = true;
process.report.directory = '/var/reports';The JSON output is structured enough to feed straight into a monitoring system. If you’ve ever had a Node.js process die in production and your only clue was a vague error message in CloudWatch, you know exactly why this matters. The report captures the full native stack, the JavaScript stack, heap statistics at crash time, and every active handle and request in the event loop.
For my team specifically, the reportOnFatalError flag alone justifies testing the upgrade. We’ve had processes OOM and disappear with nothing but a SIGKILL and zero context. Diagnostic Reports fix that.
Full ICU by Default #
This one is subtler, but it’s been a genuine pain point for years.
Node.js has historically shipped with “small ICU” — a stripped-down version of the International Components for Unicode library that only includes English locale data. If you needed Intl.DateTimeFormat to work correctly in Portuguese or Japanese, you had to either build Node from source with --with-intl=full-icu, or install the full-icu npm package and set an environment variable. Neither option is terrible; both options are annoying.
In v14, full ICU ships by default. Done.
// Before v14 (small-icu): outputs English formatting regardless of locale
new Intl.DateTimeFormat('pt-BR').format(new Date())
// "3/28/2020" -- wrong for Brazilian Portuguese
// v14 (full-icu default): correct locale formatting
new Intl.DateTimeFormat('pt-BR').format(new Date())
// "28/03/2020" -- correct
This seems trivial until you’re building a platform that operates across multiple countries. At TaskRabbit we serve markets with different date formats, number formats, and currency conventions. Having Intl work correctly out of the box eliminates a whole class of bugs that are easy to miss in testing — because your CI environment almost certainly uses the same locale as your dev machine. The bug only surfaces in production, in the market that doesn’t match your defaults. I’ve seen that happen more than once.
Other Things Worth Noting #
Optional Chaining (?.) and Nullish Coalescing (??) are enabled in v14’s V8. If you’ve been transpiling these through TypeScript or Babel, you can drop that for the v14 target. Not earth-shattering, but one less thing to configure.
There’s also AsyncLocalStorage landing as experimental. The idea: maintain context across async operations without threading it explicitly through every function call — similar to thread-local storage in other languages. I haven’t played with it enough to have an opinion yet, but the use case for request-scoped logging and distributed tracing is obvious. Worth watching.
Node.js 14 becomes the active LTS release (codename Fermium) in October 2020. If you’re sitting on Node 12 LTS today, there’s no urgency. But the diagnostic reports feature alone makes it worth standing up a staging environment and testing your workloads against it.
I’ll write more once the actual release drops and I’ve had a chance to run it against our test suite.