Cloudflare Cuts 100 TB of Memory From 1.1.1.1's DNS Cache by Rewriting Structures in Rust
Five successive changes to the in-memory data representation, from Vec to a wire-format byte buffer, reduced the size of each cache entry by 56% and freed up about 100 TB of RAM across Cloudflare's DNS resolver fleet.

Cloudflare rewrote the in-memory representation of the DNS cache used by its public resolver 1.1.1.1 and managed to reduce the average size of each entry by 56%, from 953 to 420 bytes, according to a report by InfoQ. The gain, rolled out in production between May 18 and July 6, 2026 across the entire fleet running Big Pineapple (the company's DNS platform), freed up approximately 100 TB of working-set memory, without swapping hardware or changing the name-resolution logic.
The cache in question is not small: Big Pineapple maintains more than 250 billion simultaneous entries. That changes the scale of the problem. A saving that would seem irrelevant in a small service, when multiplied by 250 billion records, becomes a difference of dozens of terabytes. "You don't get to save 100 terabytes of memory every day," summed up Cloudflare systems engineer Sebastiaan Neuteboom in a LinkedIn post cited by InfoQ.
The Five Changes to the Data Representation
The work wasn't a single rewrite, but five successive changes to how each cache entry is stored in Rust:
- Replacing
VecandStringwithBox<[T]>andBoxin fields that don't change after being inserted into the cache.VecandStringcarry extra capacity (pointer, length, and allocated capacity, usually larger than needed) because they were designed to grow. Once the data is fixed, that slack is pure waste. This change alone saved 64 bytes per entry and more than 15 TB across the entire fleet. - Unifying the answer, authority, and additional record lists into a single list with compact offsets, instead of three separate collections each with their own allocation headers.
- Packing booleans into bitflags, a classic compaction technique: instead of several
boolfields (each taking up at least 1 byte, sometimes more due to alignment), the flags become bits within a single integer. - Omitting the record's owner name when it matches the queried domain, reconstructing that information from the cache key itself at read time, instead of storing it duplicated in every entry.
- Replacing record-type enums with a contiguous byte buffer in DNS wire format.
The Bottleneck the Enums Were Hiding
The fifth change was the most labor-intensive and is the one most relevant to Rust developers dealing with structs that grow in production. The natural approach to representing different DNS record types (A, AAAA, CNAME, MX, and so on) is an enum, with each variant carrying the data specific to that type. The problem is that variants of very different sizes make the whole enum occupy the space of the largest one.
Cloudflare's initial solution was to place the larger variants behind Box, moving them to the heap and leaving only a pointer in the enum. That works to reduce the size of the enum itself, but trades one problem for another: each boxed variant becomes a separate heap allocation, and scattered allocations hurt memory locality, which is bad precisely for high-frequency cache access, full of CPU cache misses.
The final design abandons the enum and stores the record data as a contiguous byte buffer, in the DNS wire format itself (the binary format that travels over the network). That eliminates the per-record allocation overhead for good and improves locality, because the bytes sit side by side in memory instead of scattered across pointers. Frequently used record types can be copied straight from the cache into the response, without parsing. Records that carry domain names within the payload (such as CNAME or MX) still need to be interpreted when assembling the response, because of DNS name compression.
The Production Numbers
The impact measured in production, with the full rollout between May and July 2026:
- Resident memory per instance at p99: dropped from 9.3 GB to 5.3 GB.
- At p90: dropped from 6.5 GB to 3.8 GB.
- Allocations per entry: from 1.1 KB to 461 bytes.
- Cache insertion throughput: up 43%.
- Read (lookup) latency: down 19%.
Cloudflare says it will use the freed-up memory to increase cache capacity without raising total consumption, which in practice means more entries stored (more responses served from cache instead of going back to the origin) at the same infrastructure cost.
Not Every Scale Needs This
A comment on Reddit cited by InfoQ offers an important counterpoint for anyone tempted to replicate these techniques: "many of these memory tricks only pay off when you're at Cloudflare's request volume; at smaller scale, the extra indirection of putting variants in Box can hurt cache locality more than it helps." It's a direct reminder that enum boxing, manual wire buffers, and bitflags are optimizations that trade readability and maintainability for performance, and that trade-off is only worth it when the number of accesses per second and the volume of entries justify it.
How Other DNS Resolvers Solve the Same Problem
InfoQ contextualizes Cloudflare's choice by comparing it with two recursive resolvers popular in self-hosted infrastructure. According to the report, Unbound keeps separate caches (message, RRset, key, and negative cache), each with its own size and slab configuration, allowing fine-tuning per data type; this description was not confirmed in the project's official documentation among the sources consulted. Also according to InfoQ, PowerDNS Recursor uses multiple cache types, including packet cache and record cache, information likewise not verified directly in PowerDNS's documentation. Cloudflare's difference in approach, according to the report, is not having multiple specialized caches, but rather tackling the representation and allocation overhead within each individual cache entry, which makes sense when the entry itself is the bottleneck, not the layered architecture.
What This Means for Those Writing Rust in Production
The case is a replicable playbook for any Rust service with long-lived in-memory data structures, even outside the scale of billions of entries: review whether Vec/String are really necessary (or whether a Box<[T]>/Box would suffice once the data stops changing), measure whether enums with variants of very different sizes are inflating the type, and consider compact binary formats when the data already has a natural serialization format, as is the case with DNS's wire format. The central point the Cloudflare case leaves us with is that memory optimization in production rarely comes from one big change but from a sequence of representation tweaks, each measured in isolation before the next, with entry-size and allocation benchmarks tracking every step.
Translated from the Brazilian Portuguese original · Read the original
Perplexity swaps DynamoDB for in-house database and cuts latency by 5x
The company behind the AI-powered search engine migrated its serving layer to CobbleDB, an internal database written in Rust, and cut batch read latency by up to 5x while saving at least 20% on storage.