Published: October 22, 2025
3
5
48

🚀 Noop Functions vs Optional Chaining: A Performance Deep Dive I ran benchmarks comparing `noop()` vs `obj?.fn?.()` and the results surprised me. Spoiler: Noop functions are 5.5x to 8.8x faster. Here's what you need to know 🧵

Image in tweet by Matteo Collina

The setup is simple. Thehe performance difference? Massive.

Image in tweet by Matteo Collina

The numbers (5M iterations): • Noop: 939M ops/sec • Optional chaining (empty): 134M ops/sec (7x slower) • Optional chaining (with method): 149M ops/sec (6.3x slower) • Deep optional chaining: 106M ops/sec (8.8x slower) Yes, you read that right. 5.5x to 8.8x slower.

Why does this happen? Noop: V8 inlines trivial functions. The function call *completely disappears* in optimized code. Zero overhead. Optional chaining: Property lookup + null/undefined check at runtime. V8 can't optimize this away because the checks must happen.

Real-world pattern: Fastify's logger Instead of checking `logger?.info?.()` everywhere, Fastify uses abstract-logging to provide noop functions upfront. The key technique: **provide noops upfront rather than check for existence later**. V8 inlines = zero cost. 🎯

The TypeScript trap: TypeScript's type system encourages defensive coding. You mark properties as `optional?` even when runtime guarantees they exist. This leads to unnecessary `?.` everywhere "just to be safe" and satisfy the type checker. Fix your types to match reality!

Example TypeScript fix:

Image in tweet by Matteo Collina

But should you care? Context matters: even "slow" optional chaining runs at 106M+ ops/sec. For most apps, this is negligible. Use optional chaining for external data, APIs, and normal business logic. Safety first.

When noops matter: • Performance-critical hot paths • High-frequency operations • Tight loops • Code running thousands of times per request Even at a few thousand calls/request, that 5-8x difference adds up fast. Profile first, optimize second.

My recommendation: Don't premature optimize. Write code with optional chaining where it makes sense for safety and readability. But when profiling shows a bottleneck? Now you know the cost and the solution. Readable code > micro-optimizations. Until it matters.

Thanks to @simonesanfradev for creating the comprehensive benchmarks that confirmed these performance characteristics! Full article with all the details, code examples, and TypeScript tips: https://adventures.nodeland.de...

@matteocollina Please don't show this to @htmx_org and @unclebobmartin

@matteocollina that 5.5x to 8.8x hit for `obj?.fn?.()` is wild. always assumed it was cheaper than this, solid dive. 🔥

Image in tweet by Matteo Collina

new nightmare just dropped an ESM/CJS resolution bug that only manifests on windows

Image in tweet by Matteo Collina

Don't dismiss RSCs wholesale because Next.js App Router didn't fit your needs. They're actually a very flexible low level technology that I hope other frameworks build on.

A pretty practical review of RSCs. Flattered that TanStack was considered “respectful” of this devs time in the end. https://paperclover.net/blog/w...

Bun v1.3.1 - Fixes 103 issues (addressing 172 👍) - Faster `bun build` in symlink-heavy projects (especially on macOS) - Fixed Windows hang - bun test —pass-with-no-tests —only-failures - publicHoistPattern in bun install - Many bundler & runtime bugfixes https://bun.com/blog/bun-v1.3....

Share this thread

Read on Twitter

View original thread

Navigate thread

1/17