Skip to main content

MemoryStore guide

This is the end-to-end walkthrough for MemoryStore, the platform's managed, Redis-compatible key-value store. It assumes only an account and a project, and it takes you from zero to a working cache or session store.

What MemoryStore is​

MemoryStore gives you a fully managed, Redis-protocol-compatible instance. Anything you would do with redis-cli or any Redis client library works against it unchanged. Use it for caching, session storage, rate limiting, leaderboards, work queues, and the small fast state your agent's tools need.

Use cases:

  • Cache for expensive API or model calls — allkeys-lru eviction is the right default.
  • Session store for web apps and agents.
  • Rate limiting and counters — atomic increments with no risk of eviction if you keep the default noeviction policy.
  • Pub/sub and queues — the wire protocol supports the standard list and channel primitives.
  • Agent tool state — the side channel for shared state between a Serverless service and an agent.

Quick start: working instance in five commands​

# 1. sign in once
platformctl login

# 2. create a small cache
platformctl memorystore create cache --maxmemory-policy allkeys-lru
# ^ the response contains the password. Copy it; it is shown exactly once.

# 3. wait for ready
platformctl memorystore get cache

# 4. see the connection details (host, port; the password was shown at create)
platformctl memorystore get cache -o json

# 5. clean up when done
platformctl memorystore delete cache
The hostname is private

connection.host resolves only inside the platform. Your laptop cannot reach it and there is no public endpoint by default, so a redis-cli against that host from your machine hangs until its own timeout rather than failing fast.

To use it from a workload, see connect from workloads. To reach it from outside, publish it first with platformctl gateway publish.

The same flow in the Console is Data services → MemoryStore → Create instance → Connect.

Core concepts​

  • An instance is a managed, Redis-protocol-compatible server. It is the only object you create, and the platform places it for you. There is no replica: one instance serves every connection.
  • The size class (small, medium, large) sets memory. You can change it after creation — see change the size class or the durability. A shrink to a class whose limit is at or below what the instance is holding is refused rather than applied.
  • The eviction policy (noeviction by default, allkeys-lru for caches) is set at create time only.
  • Persistence (on by default) writes every change to an append-only log on a disk of its own. Turn it off (persistence.enabled: false) only if losing the data is acceptable — with no disk, any restart brings the instance back empty, including the one a size class or durability change causes. It is settable at create and cannot be changed afterwards, in either direction.
  • Durability (persistence.fsync, everysec by default) says how long an acknowledged write may sit in memory before it is on disk. Unlike persistence itself, this one is changeable after create.
  • A new instance returns its password exactly once. Later reads return only the name of the Secret that holds it.
  • The TLS endpoint is enabled at create time. (tls.enabled: true.) Required for any connection that crosses the project boundary.
  • shared mode puts this instance on the project-shared backend (cheap, fast, less isolated). dedicated mode gives the instance its own backend (louder-neighbor protection, higher cost).
  • The credential Secret lives in Secrets Manager under ms-<name>-credential once the instance is provisioned. Use it from your code, do not paste the password.
  • Rename is not supported. The name is part of the hostname. Recreate if you need a different name.
  • Every instance is project-scoped. Other projects cannot see it, list it, or reach it.

Change the size class or the durability after create​

Two settings can be changed on an instance that already exists: the size class, and the durability setting persistence.fsync. Everything else is fixed when the instance is created, and an attempt to change it is refused in words rather than accepted and ignored — see what an update refuses.

There used to be no update path at all. The only way to give an instance more memory was to delete it and create another one, which threw the data away.

platformctl memorystore update cache --size-class medium
platformctl memorystore update cache --fsync always
platformctl memorystore update cache --size-class large --fsync everysec

Only the flags you pass are sent, so a resize cannot silently revert a durability setting somebody else just chose. Passing neither is an error, not a no-op.

What it costs. A change restarts the instance once: about 30 seconds back to ready. Sending the values the instance already has changes nothing and does not restart it.

What that restart costs your data depends on one setting, and the two answers are opposite ones:

  • Persistence on (the default): the disk follows the instance to whichever machine it lands on, and it reloads the append-only file on the way back up. A graceful restart like this one costs you nothing. It is not a promise about every failure — if the machine dies mid-roll, the everysec window below still applies.
  • Persistence off: there is no disk. The instance holds the dataset in memory and nothing else, so the same restart brings it back empty. That is the whole of a cache, gone, in exchange for a resize.

The note on the API response says which of the two you are getting, in those words, before you wait for the instance to come back.

The disk does not grow with the class. persistence.size is fixed at create (2 GiB by default) and is independent of the size class, so growing an instance to a class whose memory limit approaches or exceeds its disk leaves the append-only file less room than the dataset it has to record. If that is where you are heading, create a new instance with a bigger --persistence-size and migrate — which is the path an in-place resize spares you, and still the only one there is for a disk.

Clients reconnect. Commands in flight at the moment of the restart do not survive it, so make the change when a dropped connection is cheap, or make sure your client retries.

What everysec and always actually promise​

persistence.fsync sets how long an acknowledged write may sit in memory before it is on disk. It means something only while persistence is on: with persistence off there is no disk, and a restart loses everything. Sending it to an instance with persistence off is refused with 409 rather than accepted and quietly ignored — see what an update refuses.

--fsync / persistence.fsyncWhat an acknowledgement meansWhat it costs
everysec (default)The write is handed to the machine to write out, and is on disk within about a second. A restart of the instance alone keeps it; if the machine dies, up to about one second of acknowledged writes can be lost.Nothing extra. Every instance has run this way so far.
alwaysAn acknowledged write is on disk before we acknowledge it.Every write waits for the disk before it is answered. We have not measured what that costs here, so treat it as a real, unmeasured latency cost rather than a free upgrade, and measure your own workload before you depend on a number.

Reading the value an instance is running today. The PATCH response carries persistence.fsync. No read route does yet — platformctl memorystore get and the console detail page do not show it — so until they do, the durability an instance is running is whatever you last set on it.

Neither value promises that nothing can ever be lost, and always least of all, because its promise is deliberately narrow: it is about this one instance and its own disk, at the moment of the acknowledgement. It says nothing about the disk being lost, the instance being deleted, or a machine failure that strands the disk where nothing can reach it. There is no replica and no backup behind it, so each of those is still a total loss. always protects you from a crash, not from the list in Scale, limits and recovery.

What an update refuses, and what to do instead​

What you ask forWhat you getWhat to do instead
A different persistence.size — a bigger or smaller disk400, refusedA disk cannot be grown or shrunk in place on this platform. Create a new instance at the size you want (platformctl memorystore create <new-name> --persistence-size 20Gi), copy the data across, then delete the old one. If what you wanted was more memory, that is the size class, and it is settable here.
persistence.enabled — persistence on or off400, refusedThe disk is attached when the instance is created; a running instance cannot have one added or taken away. Create a new instance and migrate.
persistence.fsync on an instance with persistence off409, refusedThere is no append-only file to flush, so the setting would change nothing and would read back as a durability level the instance does not have. Persistence cannot be turned on in place either: create a new instance with persistence enabled and migrate.
A size class whose limit is at or below what the instance is holding right now409, refused, naming both numbersDelete keys or shrink the working set first, then retry. Read the live figure with platformctl memorystore stats <name> (used_memory_bytes). An instance sitting exactly at the new ceiling is refused too: its next write fails.
Neither fieldAn error, not a silent no-opPass a size class, a durability setting, or both.

The shrink guard is the one worth understanding rather than working around, and it refuses whatever your eviction policy is. With the default noeviction, an instance that came back over its limit would not drop anything to fit: it would keep every key, keep answering reads, and fail every write — which looks like your own code breaking rather than like an outage. With allkeys-lru, or any other eviction policy, it would do the opposite and silently evict keys until the dataset fit — data you did not ask to lose. Neither is something to do to you on the strength of a resize flag. If the live usage cannot be read at all, because the instance is provisioning, restarting or unreachable, the shrink is refused too and says which: the alternative is guessing, and guessing is how a resize becomes a silent write outage.

There is no instance count, on purpose​

One instance serves every connection, and there is no setting asking for a second. Replication needs a way for clients to find the writable instance, a way to promote a survivor, and a way to keep traffic off one that is not ready to take it. None of those exist here yet, and a setting that only ever accepted 1 would read as support that is not there. Plan for a single instance with a disk, and read Scale, limits and recovery for what that means when a machine fails.

API examples​

export MS="https://api.codyhill.net"
export PROJ="$(platformctl projects list -o json | jq -r '.[0].id')"
export TOK="<session token or API key>"

Create a small cache (eviction tuned for a cache):

curl -sX POST "$MS/v1/projects/$PROJ/memorystores" \
-H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"name":"cache","size_class":"small","maxmemory_policy":"allkeys-lru","tls":{"enabled":true}}'

The response contains the only copy of the password. A later read of the same instance returns the credential name, not the value:

curl -s "$MS/v1/projects/$PROJ/memorystores/cache" -H "Authorization: Bearer $TOK"

Resize it, or change how durably it writes (admin; both fields optional, absent means unchanged):

curl -sX PATCH "$MS/v1/projects/$PROJ/memorystores/cache" \
-H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"size_class":"medium","persistence":{"fsync":"always"}}'

Live stats:

curl -s "$MS/v1/projects/$PROJ/memorystores/cache/stats" -H "Authorization: Bearer $TOK"

Rotate the credential if it leaks:

curl -sX POST "$MS/v1/projects/$PROJ/memorystores/cache/rotate-credential" \
-H "Authorization: Bearer $TOK"

CLI examples​

platformctl memorystore list # all instances
platformctl memorystore get cache # state, hostname, size_class, eviction policy
platformctl memorystore stats cache # live memory, evictions, hit ratio
platformctl memorystore create cache --size-class small --maxmemory-policy allkeys-lru
platformctl memorystore update cache --size-class medium # admin only; one restart. The data survives it with persistence on
platformctl memorystore update cache --fsync always # admin only; same restart, same condition
platformctl memorystore create big --size-class large --persistence-size 8Gi # the disk is create-time only; size it here
platformctl memorystore rotate-credential cache # admin only; issues a new password, revokes the old one
platformctl memorystore renew-credential cache # admin only; renews the existing credential lease
platformctl memorystore delete cache # admin only; drops the instance and its data

Console walkthrough​

  1. Open the Console, pick your project.
  2. Go to Data services → MemoryStore.
  3. Click Create instance. Pick a name, size class, eviction policy, and whether to enable the TLS endpoint. For a cache, choose allkeys-lru. For anything that matters, leave the default noeviction.
  4. The response shows the password once, with copy and Save to Secrets buttons. Save it to Secrets — that is the easiest way to never lose it.
  5. When the row flips to Ready, click the instance to open it. The detail page shows the private hostname, port, TLS endpoint, and live stats.
  6. To connect from your code, use the TLS endpoint, not the private hostname — see Connect from workloads.
  7. Rotate credential (admin) issues a fresh password without downtime. Delete terminates the instance.

Limits and quotas​

LimitDefault
Size classessmall (~192 MiB usable), medium, large
Instances per project10 (soft; raise via support)
Eviction policiesnoeviction (default), allkeys-lru, volatile-lru, allkeys-random, plus the standard policy set of the wire protocol
Max requests/secondbounded by the chosen size class; the stats endpoint reports the live ceiling
TTL per keyany positive value up to the protocol maximum (~2^31 ms)

The one-time password is returned only at create and at rotate. If you lose both copies, your only recovery is rotate-credential.

Troubleshooting snippets​

SymptomFirst thing to check
NOAUTH Authentication requiredThe password was wrong or rotated. platformctl memorystore get cache shows the current credential name; the value lives only in Secrets Manager.
OOM command not allowed when used memory > maxmemoryThe instance is full and the eviction policy is noeviction. Either raise the size class in place (platformctl memorystore update <name> --size-class medium), switch to allkeys-lru (recreate — the policy is fixed at create), or delete keys. Raising the class does not grow the disk: if the new class allows a dataset near the persistence.size you chose at create, create a new instance with a bigger disk instead.
Connection refused from your codeYou are using the private hostname. Use the TLS endpoint — see Connect from workloads.
state stuck at provisioningNormal for ~30 seconds on a small instance. If it stays past five minutes, check the project for a stuck resource with platformctl memorystore get cache -o json.
Lost passwordThe API will not show it again. Use rotate-credential to issue a new one.
read-only errorsThe instance went into a degraded state. stats reports master_link_status; recreate if it does not recover in a few minutes.

Security notes​

  • Password shown once is a hard rule. Anything else would be a silently-leaking secret. Pair the create call with an immediate Secrets Manager write.
  • TLS endpoint when crossing the project line. Traffic inside the project's services runs over mutual TLS already. The moment a laptop, CI runner, or external tool connects, use the TLS endpoint and validate the server certificate.
  • Eviction policy and durability are a security choice. noeviction plus persistence is the safest; allkeys-lru without persistence is the fastest. --fsync always means an acknowledged write is on disk before we acknowledge it, at the cost of write latency, and still leaves you with one copy of the data. Do not put authentication tokens in a allkeys-lru cache — a full cache will silently log your users out.
  • Delete is irreversible. There is no soft-delete, snapshot, or point-in-time restore. Export anything that matters with connect before calling delete.
  • Audit is on. Every create, update, rotate, renew, and delete lands in the project's audit log with the actor, the time, and the previous credential name where applicable. An update records the size class and the durability setting before and after, so a resize is traceable to whoever asked for it.

Where next​

  • Connect from workloads — TLS, service accounts, and example client code in every common language.
  • Use with agents — where the agent's chat history actually lives, and when to give it its own store.
  • Quickstart — the five-minute standalone version.