@southpolesteve: Zod 4.5 comes with a massive drop in memory usage. If you are running in @Cloudflare Workers you should update!
Summary
Zod 4.5 implements method memoization to drastically reduce memory usage, achieving up to 9.8x less heap retention than previous versions.
View Cached Full Text
Cached at: 08/30/26, 10:24 PM
Zod 4.5 comes with a massive drop in memory usage. If you are running in @Cloudflare Workers you should update! https://t.co/8fqmYCruBp
Reducing Zod’s memory footprint by an order of magnitude with method memoization
Source: https://zod.dev/blog/reducing-memory-footprint Zod 4.5 implements a “method memoization” pattern that allows it to defer allocating memory for bound methods until they are used (if ever). This post discusses that pattern.
In Zod 4.4 a barez\.string\(\)retained 7.5kb of heap. In Zod 4.5 it retains 784 bytes.
Retained heap per schema instance, Zod 4.4.3 vs 4.5 (benchmark)By default all methods on Zod schemas areauto-bound, meaning they do not rely on implicitthissemantics to work properly. That enables patterns like this, which otherwise may break or behave in unexpected ways when reliant on unbound prototype methods.
This is often useful for preventing unexpected behavior in certain uncommon circumstances. There’s apackage on npmthat specifically implements some auto-bind utilities. But there’s a downside, which is that every method is now a bound closure that takes up space in memory. It’s no longer possible for multiple instances of one class to share a method via regular prototype chain inheritance.
This is now conclusively fixed in Zod 4.5 via a pattern I’ve been calling “method memoization”.
Zod classes define their methods asgetterson a standardprototype. The first time an instance’s method is accessed, it falls through to the prototype via standard prototype inheritance. The getter returns a method implementation that’s bound to the accessing instance and*assigns it as anown property*to the instance, effectively memoizing it forever. Successive accesses on that same method thus avoid getter-invocation overheads and resolve directly from the own property.
It’s a more sophisticated variant of the self-overwriting getter I’ve described before.
An instance method that’s never used (and most aren’t!) is never materialized, nor is it ever stored as an own property on the instance.
schema4.4.34.5smallerz\.string\(\)7.5kb784b9.8xz\.number\(\)4.4kb706b6.4xz\.boolean\(\)3.6kb594b6.3xz\.literal\("a"\)5.1kb1.7kb3.0xz\.enum\(\[\.\.\.\]\)5.3kb1.5kb3.5xz\.email\(\)5.8kb2.2kb2.7xz\.uuid\(\)5.9kb2.2kb2.6xz\.iso\.datetime\(\)6.1kb2.5kb2.4xz\.string\(\)\.min\(1\)16.7kb3.4kb5.0xz\.string\(\)\.min\(1\)\.max\(5\)25.8kb6.0kb4.3xz\.string\(\)\.optional\(\)12.6kb1.5kb8.4xz\.string\(\)\.nullable\(\)13.1kb1.5kb8.8xz\.string\(\)\.default\(""\)13.1kb1.9kb7.1xz\.string\(\)\.brand\(\)7.6kb872b8.9xz\.string\(\)\.refine\(\.\.\.\)20.5kb4.4kb4.7xz\.string\(\)\.transform\(\.\.\.\)17.5kb2.0kb8.5xz\.string\(\)\.pipe\(\.\.\.\)21.4kb2.2kb9.6xz\.array\(z\.string\(\)\)11.2kb1.9kb5.8xz\.tuple\(\[\.\.\.\]\), 3 items15.7kb2.8kb5.7xz\.record\(\.\.\.\)16.4kb2.6kb6.2xz\.object\(\{\}\)6.6kb3.3kb2.0xz\.object\(\{\.\.\.\}\), 3 keys22.2kb5.3kb4.2xz\.object\(\{\.\.\.\}\), 10 keys82.0kb11.0kb7.5xz\.union\(\[\.\.\.\]\), 2 options17.5kb2.1kb8.3xz\.discriminatedUnion\(\.\.\.\), 2 options42.0kb12.7kb3.3xz\.lazy\(\.\.\.\)5.9kb1.3kb4.5xzod/mini``z\.string\(\)2.5kb577b4.4xzod/mini``z\.object\(\{\.\.\.\}\), 3 keys11.8kb3.2kb3.7x
The problem with the old approach is exacerbated by a detail of V8’s memory allocation around an object’s own properties.
- With fewer than 13 own properties, V8 tracks them in a compact 128-byte backing store
- With 13 or more, V8 bumps the store up to 848 bytes
- With 21 or more, it steps again to 1616 bytes
A regular string schema in\[email protected\]carried 49 own properties (40 methods and 9 properties) so every instance got the 1616-byte backing store.
Under the new system there are only six eagerly bound properties:\_zod,def,type,format,minLength, andmaxLength. Everything else lives on the memoizing prototype.
Retained bytes can be tricky to measure. The numbers above come frompackages/bench/memory/schema\-footprint\.tsin the repo.
Upgrade to Zod 4.5 for these enhancements.
Similar Articles
Saving 100 terabytes of memory by optimizing 1.1.1.1's DNS cache
Cloudflare optimized their 1.1.1.1 DNS cache to reduce memory usage by over 50%, saving 100 terabytes of memory while improving performance through refined Rust data structures.
@DODOREACH: https://x.com/DODOREACH/status/2067571689634894251
After three months using Hermes Agent, the author shares insights on memory management and profile optimization, finding that less memory and fewer profiles lead to better results.
@charliermarsh: Since my last post, I reduced ty’s retained memory by another 15% with Codex. We're now at a ~25% memory reduction over…
Developer @charliermarsh reports reducing ty's retained memory by another 15% using Codex, achieving a total ~25% memory reduction via /goal, and expresses enthusiasm for GPT models.
Workers Cache
Cloudflare launches Workers Cache, a tiered cache that sits in front of Workers, allowing cached responses to be served without invoking the Worker, reducing CPU time and improving performance.
@billtheinvestor: Give Claude Code and Codex infinite memory, programming efficiency improved by 92%! The Agentmemory tool has quickly gained 4000+ stars on GitHub and is completely free. It saves all information from your coding sessions through smart compression, and automatically extracts relevant context in future sessions, avoiding re...
Agentmemory is an open-source tool that provides infinite memory for Claude Code and Codex, reducing token usage through intelligent compression, improving programming efficiency, and has gained 4000+ stars on GitHub.