The Node (and more) Banter

Node.js Left 26% Performance on the Table for 10 Years

31 min · 17 de jun de 2026
Portada del episodio Node.js Left 26% Performance on the Table for 10 Years

Descripción

A default set in May 2015 just got its first change. One constant. One number. And it was silently costing Node.js up to 26% throughput on some of the most common workloads in the ecosystem: file reads, HTTP parsing, stream chunking. Nobody broke it. Nobody was ignoring it. It was just stuck in a world that no longer existed. In this episode of The Node (and more) Banter, Luca Maraschi and Matteo Collina explain how they investigated a small but important change that was just released in Node.js 26.3.0. They discuss how modern applications moved past an old assumption, why multi-threaded apps suffered the most, and what it takes to show that a simple fix is safe for millions of users. In this episode, we cover: ✅ How a default set in 2015 quietly stopped making sense as applications and hardware evolved ✅ Why the fix helped some workloads by 26%, and had zero impact on others ✅ How Matteo traced the slowdown all the way down to the operating system level to understand what was really happening ✅ The cost of the change, and how to think about whether it matters for your own application The takeaway? The biggest performance gains often don’t come from major rewrites. Sometimes, it’s just a setting that made sense years ago and was never revisited. The real lesson is about the assumptions built into the tools you use daily, and what can change when someone finally checks them.

Comentarios

0

Sé la primera persona en comentar

¡Regístrate ahora y únete a la comunidad de The Node (and more) Banter!

Prueba gratis

Empieza 7 días de prueba

$99 / mes después de la prueba. · Cancela cuando quieras.

  • Podcasts solo en Podimo
  • 20 horas de audiolibros al mes
  • Podcast gratuitos

Todos los episodios

64 episodios

episode Node.js Left 26% Performance on the Table for 10 Years artwork

Node.js Left 26% Performance on the Table for 10 Years

A default set in May 2015 just got its first change. One constant. One number. And it was silently costing Node.js up to 26% throughput on some of the most common workloads in the ecosystem: file reads, HTTP parsing, stream chunking. Nobody broke it. Nobody was ignoring it. It was just stuck in a world that no longer existed. In this episode of The Node (and more) Banter, Luca Maraschi and Matteo Collina explain how they investigated a small but important change that was just released in Node.js 26.3.0. They discuss how modern applications moved past an old assumption, why multi-threaded apps suffered the most, and what it takes to show that a simple fix is safe for millions of users. In this episode, we cover: ✅ How a default set in 2015 quietly stopped making sense as applications and hardware evolved ✅ Why the fix helped some workloads by 26%, and had zero impact on others ✅ How Matteo traced the slowdown all the way down to the operating system level to understand what was really happening ✅ The cost of the change, and how to think about whether it matters for your own application The takeaway? The biggest performance gains often don’t come from major rewrites. Sometimes, it’s just a setting that made sense years ago and was never revisited. The real lesson is about the assumptions built into the tools you use daily, and what can change when someone finally checks them.

17 de jun de 202631 min
episode Performance/Memory tradeoff. Can we have both instead? artwork

Performance/Memory tradeoff. Can we have both instead?

Memory and performance often compete with each other. Most developers only notice this tradeoff when something goes wrong, not during the initial design. At that point, the key decisions are already set. In this episode of The Node (and more) Banter, Luca Maraschi and Matteo Collina talk about the memory-performance tradeoff from two sides: how to plan for it during design, and how to handle it at runtime if it becomes an issue. They use flame graphs on Kafka workloads to reveal hidden bottlenecks and explain a clear approach that makes memory debugging more reliable. This episode covers: ✅ Why the memory-performance tradeoff begins at design time, not after your app crashes ✅ How to find this tradeoff in your architecture before you start coding ✅ How flame graphs work in real situations and what they show about Kafka pipelines that other tools miss ✅ A step-by-step way to debug memory issues without guessing. The takeaway? The chicken-and-egg problem is not something you solve once and for all, but something you learn to manage. Developers who think about it during design build systems that don't cause late-night surprises. Flame graphs simply help you spot what you should have planned for.

10 de jun de 202635 min
episode How Do We Scale Rate Limiting in Node.js? artwork

How Do We Scale Rate Limiting in Node.js?

Your Node.js service has rate limiting. You tested it, it worked, you shipped it. But your limit lives in the memory of a single process, and the moment you run more than one instance behind a load balancer, every replica enforces its own private budget. Ten instances means ten times the traffic you thought you were allowing. That is not a smaller problem at scale, it is a different problem entirely. So what does rate limiting that actually holds across a cluster look like? In this episode of The Node (and more) Banter, Luca Maraschi and Matteo Collina dig into rate limiting for Node.js applications, why the obvious approach quietly fails in production, and how to build limits that survive horizontal scaling. In this episode, we cover: ✅ The mechanics of in-process rate limiting and the trap of the in-memory store. ✅ Why per-instance counters cannot enforce a global limit once you scale out. ✅ How to back rate limiting with a shared store like Redis or Valkey, and the patterns that actually work. ✅ The operational realities: clock skew across nodes, what happens when your shared store goes down, and the consistency-versus-performance balance you have to choose. The takeaway? A rate limit is a promise about your whole system, not one process. If it only holds on a single instance, it is lying to you. Get distributed rate limiting right, and Node.js handles abuse and traffic spikes gracefully. Get it wrong, and you will find out the hard way, in production, under load.

3 de jun de 202630 min
episode Requests, Limits, and the Throttling Trap: K8s Resources for Node.js artwork

Requests, Limits, and the Throttling Trap: K8s Resources for Node.js

You set a CPU limit on your pod, the node has plenty of capacity to spare, and yet your Node.js service is throttled to a crawl. How does that happen? The answer lives deep in the Linux kernel, in the CFS bandwidth controller and cgroups, and most teams never look there. Requests and limits are not two knobs for the same thing. One drives scheduling, the other enforces a hard quota, and confusing them is how you end up paying for CPU you can never actually use. So how do you size them right for an event-loop runtime? In this episode of The Node (and more) Banter, Luca Maraschi and Matteo Collina break down how Kubernetes CPU and memory allocation actually works, what requests and limits really do at the kernel level, and why the defaults quietly sabotage Node.js workloads. In this episode, we cover: ✅ What CPU requests and limits actually mean, and why they are not interchangeable. ✅ How CFS quota and cgroups cause throttling even when the node is mostly idle. ✅ The three QoS classes (Guaranteed, Burstable, BestEffort) and which one fits a Node.js service. ✅ Why a single-threaded runtime makes limit sizing trickier than it looks, and the patterns that avoid silent throttling. The takeaway? Kubernetes will give you exactly what you asked for, including the throttling you did not mean to ask for. Get requests and limits right and your Node.js services run predictably. Get them wrong and you will burn money on capacity the scheduler will never let you touch.

27 de may de 202628 min
episode Should We Rewrite Node.js in Rust? artwork

Should We Rewrite Node.js in Rust?

Bun made the switch. Zig is out, Rust is in, and AI handled most of the work, with 98% of the test suite passing. The question is no longer hypothetical; it's real now. If an AI can port an entire runtime, why are so many enterprise teams still stuck on a Node 12 codebase they're afraid to update? In this episode of The Node (and more) Banter, Luca Maraschi and Matteo Collina talk about the Bun Zig-to-Rust port, including the memory leaks that led to the change, the rumors around it, and what it means that AI made it happen. They also look at the bigger picture: meta-cloud platforms losing their advantage, Node.js downloads passing 680 million a month thanks to AI tools, and why major AI companies still don't have a seat on the Node.js TSC, even though they build billions of dollars of products on it. In this episode, we cover: ✅ Why Bun is moving from Zig to Rust, and why memory safety matters more than the drama ✅ How AI managed to port a full runtime with 98% of tests passing, and what made this possible ✅ The key to AI-powered migrations: integration tests that focus on results, not how things are built ✅ Can enterprise teams do the same, and what does upgrading from Node 12 to Node 24 with AI really look like? The takeaway? The real breakthrough wasn't the model, but the test suite. Without integration tests, there is no migration, whether you use AI or not. That's the lesson hidden in the Bun story, and it's one most teams will miss while debating Rust versus Zig.

20 de may de 202629 min