PropertiesService Is Not a Database: the 9KB Wall
A Properties value caps near 9KB. Cache only data you can lose. Big state goes to Sheet, Drive, or an external DB. Plain JSON loses types.
PropertiesService is a small store, not a database. Each value caps near 9KB, and the whole store is limited too. Keep a cursor, small config, or an idempotency key there; send anything bigger elsewhere.
Why it matters
Start with “store state as JSON in Properties” and one day, when the data grows, it silently fails at 9KB. And state kept only in cache disappears when the TTL expires. Putting data you can’t lose into volatile storage is where the accident begins.
Storage choice rule
| Store | Use | Limit |
|---|---|---|
| CacheService | Disposable acceleration cache | 100KB/key, TTL-based |
| PropertiesService | Cursors, config, flags | ~9KB/value |
| Sheet | User-visible tabular state | 50,000 chars/cell |
| Drive JSON | Larger opaque state (manage the file) | File size |
| External DB | Multi-user, query-heavy, high-volume | — |
The key question: can the data be lost? That answer splits CacheService from the rest.
Plain JSON loses types
JSON.stringify()/parse() alone won’t safely restore Date, Map, Set, undefined, or NaN.
// store Date as an ISO string, restore on read
const replacer = (k, v) => (v instanceof Date ? { __d: v.toISOString() } : v);
const reviver = (k, v) => (v && v.__d ? new Date(v.__d) : v);
props.setProperty("job", JSON.stringify(state, replacer));
const state = JSON.parse(props.getProperty("job") || "{}", reviver);
Deeper: chunk caches over 100KB
One CacheService key caps at 100KB. For larger values, split into chunks across keys with a reassembly key. And a cache must always have a recompute path.
One line to keep: small → Properties, disposable → Cache, big → Sheet/Drive/DB. Protect types with a replacer/reviver.
Frequently asked questions
- Why does storing JSON state in PropertiesService silently fail?
- Each value caps near 9KB, so as data grows it fails without a clear error. Keep only a cursor, small config, or an idempotency key there; send larger state to Sheet, Drive, or an external DB.
- When should I use CacheService versus PropertiesService?
- CacheService (100KB per key, TTL-based) is for disposable acceleration data you can afford to lose. PropertiesService (about 9KB per value) is for durable cursors, config, and flags.
- Which JavaScript types does plain JSON serialization fail to restore safely?
- Date, Map, Set, undefined, and NaN are not safely restored by JSON.stringify/parse alone. Use an explicit replacer and reviver to protect those types.