---
layout: post
title: "Cached list queries now use up to 69% less memory and serve up to 29% more requests"
description: Appwrite now serializes key-value cache entries in a binary format instead of JSON. Cached list responses consume up to 69% less memory, and cached list throughput increases by up to 29%.
date: 2026-10-07
cover: /images/blog/faster-list-caching-binary-format/cover.avif
timeToRead: 5
author: luke-silver
category: announcements, performance
featured: false
callToAction: true
faqs:
  - question: "Do I need to change my code to get the faster cache?"
    answer: "No. Queries that already pass a `ttl` to `listRows` get the smaller, faster cache entries. The change is inside Appwrite's cache layer, so the SDK calls and the API responses stay the same."
  - question: "How much less memory does a cached list response use?"
    answer: "A cached page of 25 rows is 37% smaller, a page of 100 rows is 50% smaller, and a page of 1,000 rows or more is 67% to 69% smaller. A cached page of 5,000 rows drops from 3.38 MB to 1.06 MB."
  - question: "How much faster are cached list queries?"
    answer: "In benchmarks on self-hosted Appwrite 2.3, a server handled 5% more cached requests per second for pages of 25 rows and 20% to 29% more for pages of 250 rows or more. Latency for a single cached page of 1,000 rows dropped from 42.0 ms to 32.6 ms."
  - question: "Why does the speedup stop growing at larger page sizes?"
    answer: "The binary format only speeds up the cache read. Appwrite still converts every response to JSON before it sends it to the client, and that work also grows with the page size. Cache memory has no such conversion step, so the memory saving keeps growing up to 69%."
  - question: "Do self-hosted instances need a migration to use the new format?"
    answer: "No. After the upgrade to Appwrite 2.3, Appwrite reads an old JSON cache entry as a cache miss, loads the data from the database, and writes the entry again in the binary format. Cache misses rise for a short time after the upgrade."
  - question: "Do requests without a TTL get faster too?"
    answer: "Yes, by a smaller margin. Appwrite also stores sessions, API keys, and table schemas in the key-value cache, and those entries now use the binary format too. Uncached requests in the benchmark were about 5% faster, which is smaller than the gain for TTL-cached lists."
---

The [TTL cache for list queries](/blog/post/announcing-list-cache-ttl) lets Appwrite serve a repeated `listRows` call from the key-value cache instead of the database. On a cache hit, Appwrite reads the stored entry, deserializes it into rows, and builds the response.

Appwrite now stores that cache in a binary format instead of JSON. Each cached page is smaller, and Appwrite reads it faster. In benchmarks, cached list queries used up to **69% less memory** and served up to **29% more requests per second**.

# The cache now uses a binary format instead of JSON

Appwrite previously serialized every cache entry as JSON. Because JSON is a text format, each row in a cached page repeats every column name, and numbers are stored as strings of digits. Every cache hit required parsing the full payload.

The cache now uses a compact binary serialization format. It stores each repeated string, such as a column name, once per entry and encodes numbers natively. Appwrite writes and reads fewer bytes per entry and spends less CPU time on deserialization.

Larger pages repeat the same column names more times, so they get the biggest saving.

# Cached pages use up to 69% less memory

![Cache size per cached page, JSON compared with binary](/images/blog/faster-list-caching-binary-format/cache-memory.avif)

The table shows the size of one cached page in the key-value cache for each page size.

| Rows per page | JSON | Binary | Reduction |
|---|---|---|---|
| 25 | 16.3 KB | 10.3 KB | 37% |
| 100 | 66.6 KB | 33.6 KB | 50% |
| 250 | 167.8 KB | 64.4 KB | 62% |
| 1,000 | 672.8 KB | 218.9 KB | 67% |
| 5,000 | 3.38 MB | 1.06 MB | 69% |

The same cache memory now holds about **three times** as many cached pages of 1,000 rows.

The saving applies to the whole cache. After a mixed workload of 200 cached queries, 500 single-row reads, and the table schemas, the full cache used **2.65 MB** instead of **5.66 MB**.

# Cached list queries serve up to 29% more requests

![Cached listRows requests per second for each page size](/images/blog/faster-list-caching-binary-format/throughput.avif)

One Appwrite server handled these cached `listRows` requests per second, with 8 requests in flight at a time.

| Rows per page | JSON | Binary | Change |
|---|---|---|---|
| 25 | 508 | 533 | +5% |
| 50 | 445 | 485 | +9% |
| 100 | 350 | 398 | +14% |
| 250 | 215 | 267 | +24% |
| 500 | 146 | 175 | +20% |
| 1,000 | 85 | 109 | +29% |
| 2,500 | 38.7 | 47.6 | +23% |
| 5,000 | 19.0 | 24.3 | +28% |

The gain stops growing at about 1,000 rows. The binary format only speeds up the cache read. Appwrite still converts each response to JSON before it sends it to the client, and a page of 5,000 rows is 3.4 MB of JSON. That work also grows with the page size, so it limits the gain. Cache memory has no such conversion step, so the memory saving keeps growing.

# Single cached requests are up to 22% faster

![Response time for one cached request of 1,000 and 5,000 rows](/images/blog/faster-list-caching-binary-format/response-time.avif)

At a concurrency of one, latency for a cached page of 1,000 rows dropped from **42.0 ms** to **32.6 ms**. For a page of 5,000 rows, latency dropped from **217.8 ms** to **175.0 ms**.

# Requests without a TTL are slightly faster

Appwrite also uses the key-value cache for data it reads on almost every request, such as sessions, API keys, and table schemas. These entries now use the binary format too. Requests that don't use a TTL, such as a single `getRow` call or a call for the signed-in account, were about **5%** faster in the benchmark.

# How the benchmark ran

- The test used self-hosted Appwrite 2.3 on a single machine, with a TablesDB table of 10,000 rows. The table had text, enum, array, integer, float, boolean, and datetime columns.
- Both runs used the same server and the same data. The only difference was the cache format.
- The runs alternated between JSON and binary 8 times, with the cache cleared before each run. The tables show the median of 4 runs for each format.
- Each page size got up to 3,000 measured requests after a warm-up, and every request succeeded.

# Availability

The binary cache format ships in self-hosted Appwrite 2.3, so the memory and throughput improvements in this post apply to self-hosted instances after the upgrade. Self-hosted instances need no migration and no cache flush. After the upgrade, Appwrite reads an old JSON entry as a cache miss, loads the data from the database, and writes the entry again in the binary format. Cache misses rise for a short time after the upgrade.

# Resources

- [Rows: Cache list responses](/docs/products/databases/tablesdb/rows#cache-list-responses)
- [Pagination: Cache list responses](/docs/products/databases/tablesdb/pagination#cache-list-responses)
- [Announcing list response caching](/blog/post/announcing-list-cache-ttl)
- [Benchmarking TTL list caching](/blog/post/ttl-cache-performance-benchmark)
- [Upgrade a self-hosted instance](/docs/advanced/self-hosting/production/updates)
- [Join the Appwrite Discord](https://appwrite.io/discord)
