<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/optimizing-objects-with-null-prototypes-ut2gbadbw" -->

---
title: Optimizing objects with null prototypes | daily.dev
description: Objects created with a null prototype (like `{ __proto__: null }` or `Object.create(null)`) get permanently trapped in V8's slower dictionary mode, unlike...
canonical: https://daily.dev/posts/optimizing-objects-with-null-prototypes-ut2gbadbw
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Optimizing objects with null prototypes | daily.dev
og:description: Objects created with a null prototype (like `{ __proto__: null }` or `Object.create(null)`) get permanently trapped in V8's slower dictionary mode, unlike...
og:url: https://daily.dev/posts/optimizing-objects-with-null-prototypes-ut2gbadbw
og:image: https://api.daily.dev/og/posts/Ut2GbAdbw.png
og:image:alt: Optimizing objects with null prototypes
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Optimizing objects with null prototypes

**[Adventures in Nodeland](https://daily.dev/sources/nodeland)** · 6 min read · 84 upvotes · 4 comments

## Summary

Objects created with a null prototype (like `{ __proto__: null }` or `Object.create(null)`) get permanently trapped in V8's slower dictionary mode, unlike objects whose prototype is nulled after creation via `Object.setPrototypeOf` or via a class whose prototype is null-protoed, which stay fast. This distinction was discovered while optimizing Node.js core's WebStreams implementation: converting per-stream state records from null-prototype literals to a null-protoed class doubled pipe-to throughput (+105-112%), with WritableStream creation up 204% and ReadableStream up 138%. A second fix on module-level sentinel objects yielded smaller but still measurable gains (6.5-17.6%). The takeaway is that this only matters on genuinely hot paths — one-off uses of `__proto__: null` cost nothing measurable.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://adventures.nodeland.dev/archive/optimizing-objects-with-null-prototypes>

## Questions this post answers

### Why does creating an object with { __proto__: null } make it slower in V8?

Any object created with a null prototype at creation time enters V8's dictionary mode, storing properties in a hash table instead of behind a fast hidden class. This makes literal creation roughly 500-1500 ns versus about 30 ns for a normal literal, and every subsequent property read stays a slow dictionary lookup rather than an inline-cache hit, even after heavy reuse.

_Developers chasing V8 performance regressions can find deep-dive breakdowns like this one on daily.dev._

### How do I keep an object fast in V8 while still giving it a null prototype?

Instead of writing { __proto__: null } as a literal, create the object normally and then call Object.setPrototypeOf(obj, null), or use a class whose prototype has been null-protoed with Object.setPrototypeOf(ClassName.prototype, null). Both approaches inherit the object's fast hidden-class map and avoid ever entering V8's dictionary mode, unlike a null-prototype literal or Object.create(null).

_For teams optimizing hot paths in Node.js, daily.dev surfaces practical V8 tuning techniques like this._

### What performance gain did Node.js core get from fixing null-prototype objects in WebStreams?

Converting four per-stream null-prototype state records to null-protoed class instances roughly doubled pipe-to throughput (+105-112%), with WritableStream creation 204% faster, ReadableStream 138% faster, and TransformStream 134% faster. A separate fix to two module-level sentinel objects (kNilRequest and kNilPendingAbortRequest) added pipe-to gains of 12.3-14.9% and writer-driven write gains of 6.5-17.6%.

_Anyone benchmarking Node.js internals can track concrete numbers like these via daily.dev._

## Community discussion

Top comments from developers on daily.dev.

**@bob72** · 2 upvotes

> Okay, this is slow, but why would anyone access objects this way? Now I am wondering what about assigning to null? Is there any difference?

**@jenueldev** · 2 upvotes

> The class-based workaround is a useful reminder that semantic equivalence in JavaScript does not guarantee the same optimization path in V8. The practical takeaway feels nicely scoped: keep null-prototype literals where clarity and safety matter, but benchmark alternative shapes on genuinely hot allocation paths before accepting extra complexity.

**@ristotoldsep** · 0 upvotes

> Nice find. V8 has a gift for making ‘obvious’ optimizations weird.

**@agustinbarrientos** · 0 upvotes

> Does the class approach still help when properties keep getting deleted? A map with unpredictable keys seems like a different case.

## Similar posts on daily.dev

- [No, We Can't Harden Node.js Against Prototype Pollution](https://daily.dev/posts/no-we-can-t-harden-node-js-against-prototype-pollution-agutzkidu) · Adventures in Nodeland · 98 upvotes · 2 comments
- [How \_\_proto\_\_, prototype, and Inheritance Actually Work in JavaScript](https://daily.dev/posts/how-proto-prototype-and-inheritance-actually-work-in-javascript-zlsteblbp) · freeCodeCamp · 4 upvotes · 0 comments
- [Property-Based Testing Caught a Security Bug I Never Would Have Found](https://daily.dev/posts/property-based-testing-caught-a-security-bug-i-never-would-have-found-498pmhojr) · Kiro · 1 upvotes · 0 comments
- [Simplifying JavaScript Prototypes in Constructor Invocation](https://daily.dev/posts/simplifying-javascript-prototypes-in-constructor-invocation-o5gw2maba) · Telerik · 0 upvotes · 0 comments
- [We Ralph Wiggumed WebStreams to make them 10x faster](https://daily.dev/posts/we-ralph-wiggumed-webstreams-to-make-them-10x-faster-otxpvgii5) · Vercel · 39 upvotes · 1 comments

---

Tags: [#javascript](https://daily.dev/tags/javascript), [#performance](https://daily.dev/tags/performance), [#nodejs](https://daily.dev/tags/nodejs), [#v8](https://daily.dev/tags/v8)

[View this post on daily.dev](https://daily.dev/posts/optimizing-objects-with-null-prototypes-ut2gbadbw)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Optimizing objects with null prototypes","url":"https://daily.dev/posts/optimizing-objects-with-null-prototypes-ut2gbadbw","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/optimizing-objects-with-null-prototypes-ut2gbadbw"},"datePublished":"2026-09-27T15:59:33.126Z","dateModified":"2026-09-27T15:59:59.903Z","description":"Objects created with a null prototype (like `{ __proto__: null }` or `Object.create(null)`) get permanently trapped in V8's slower dictionary mode, unlike...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e1634d2bed8977f2b0bf19bdf64a339e?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e1634d2bed8977f2b0bf19bdf64a339e?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Adventures in Nodeland","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Adventures in Nodeland","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/4ec40f35e6e440c7ab313b37d0039595","url":"https://daily.dev/sources/nodeland"},"commentCount":4,"discussionUrl":"https://daily.dev/posts/optimizing-objects-with-null-prototypes-ut2gbadbw","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":84},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":4}],"keywords":"javascript,performance,nodejs,v8","timeRequired":"PT6M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Adventures in Nodeland","item":"https://daily.dev/sources/nodeland"},{"@type":"ListItem","position":3,"name":"Optimizing objects with null prototypes"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/optimizing-objects-with-null-prototypes-ut2gbadbw","comment":[{"@type":"Comment","text":"Okay, this is slow, but why would anyone access objects this way? Now I am wondering what about assigning to null? Is there any difference?","datePublished":"2026-09-27T19:35:43.025Z","dateModified":"2026-09-27T19:35:55.179Z","url":"https://daily.dev/posts/Ut2GbAdbw#c-eI0JRhdqN","author":{"@type":"Person","name":"Bob","url":"https://daily.dev/bob72","image":"https://avatars.githubusercontent.com/u/193962566?v=4"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":2}},{"@type":"Comment","text":"The class-based workaround is a useful reminder that semantic equivalence in JavaScript does not guarantee the same optimization path in V8. The practical takeaway feels nicely scoped: keep null-prototype literals where clarity and safety matter, but benchmark alternative shapes on genuinely hot allocation paths before accepting extra complexity.","datePublished":"2026-09-28T03:56:28.492Z","url":"https://daily.dev/posts/Ut2GbAdbw#c-beNmoyhas","author":{"@type":"Person","name":"Jenuel Oras Ganawed","url":"https://daily.dev/jenueldev","image":"https://media.daily.dev/image/upload/s--BadmiNyj--/f_auto/v1787625077/avatars/avatar_JJtZr4Sjm?_a=BAMAMicg0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":2}},{"@type":"Comment","text":"Nice find. V8 has a gift for making ‘obvious’ optimizations weird.","datePublished":"2026-09-28T09:42:06.711Z","url":"https://daily.dev/posts/Ut2GbAdbw#c-7OePAZ9LT","author":{"@type":"Person","name":"Risto Tõldsep","url":"https://daily.dev/ristotoldsep","image":"https://lh3.googleusercontent.com/a/ACg8ocLDWc6mZn0JwNmXXw6WY0L_HJ6pegzRttooC5VgtXESHSj3MNYx=s96-c"}},{"@type":"Comment","text":"Does the class approach still help when properties keep getting deleted? A map with unpredictable keys seems like a different case.","datePublished":"2026-10-01T21:37:55.386Z","url":"https://daily.dev/posts/Ut2GbAdbw#c-ELj7dKkTP","author":{"@type":"Person","name":"Agustin Barrientos","url":"https://daily.dev/agustinbarrientos","image":"https://media.daily.dev/image/upload/s--5ayxQnqn--/f_auto/v1788281802/avatars/avatar_wQYYVe5Tbj0NJ7C7qPoa8?_a=BAMAMicg0"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/optimizing-objects-with-null-prototypes-ut2gbadbw#faq","mainEntity":[{"@type":"Question","name":"Why does creating an object with { __proto__: null } make it slower in V8?","acceptedAnswer":{"@type":"Answer","text":"Any object created with a null prototype at creation time enters V8's dictionary mode, storing properties in a hash table instead of behind a fast hidden class. This makes literal creation roughly 500-1500 ns versus about 30 ns for a normal literal, and every subsequent property read stays a slow dictionary lookup rather than an inline-cache hit, even after heavy reuse. Developers chasing V8 performance regressions can find deep-dive breakdowns like this one on daily.dev."}},{"@type":"Question","name":"How do I keep an object fast in V8 while still giving it a null prototype?","acceptedAnswer":{"@type":"Answer","text":"Instead of writing { __proto__: null } as a literal, create the object normally and then call Object.setPrototypeOf(obj, null), or use a class whose prototype has been null-protoed with Object.setPrototypeOf(ClassName.prototype, null). Both approaches inherit the object's fast hidden-class map and avoid ever entering V8's dictionary mode, unlike a null-prototype literal or Object.create(null). For teams optimizing hot paths in Node.js, daily.dev surfaces practical V8 tuning techniques like this."}},{"@type":"Question","name":"What performance gain did Node.js core get from fixing null-prototype objects in WebStreams?","acceptedAnswer":{"@type":"Answer","text":"Converting four per-stream null-prototype state records to null-protoed class instances roughly doubled pipe-to throughput (+105-112%), with WritableStream creation 204% faster, ReadableStream 138% faster, and TransformStream 134% faster. A separate fix to two module-level sentinel objects (kNilRequest and kNilPendingAbortRequest) added pipe-to gains of 12.3-14.9% and writer-driven write gains of 6.5-17.6%. Anyone benchmarking Node.js internals can track concrete numbers like these via daily.dev."}}]}
```

