Skip to content

TTL

Every frame carries a TTL (time-to-live) that sets how long the store keeps it. The default is forever. A frame’s TTL is fixed when it is appended and never changes afterward.

Kinds

TTLQuery formMeaning
Foreverforever (default)Kept indefinitely.
EphemeralephemeralNever written to the store. Only readers following live at the moment of the append see it.
Timetime:<ms>Kept for <ms> milliseconds after the frame’s creation, then removed.
Lastlast:<n>Retains only the newest n frames on the frame’s topic (n >= 1); older frames on that topic are removed.

Setting a TTL

From Nushell, pass --ttl to .append:

Terminal window
"hello" | .append greeting # forever (default)
{tick: true} | .append clock --ttl ephemeral
{level: "debug"} | .append logs --ttl time:60000 # 60s
$state | .append game.score --ttl last:1 # keep only the latest

Over HTTP, set the ttl query parameter on the append endpoint (?ttl=last:1). The wire forms are exactly the query strings in the table above.

How each kind behaves

  • forever is the default, and the right choice for anything another part of the system reads back later.
  • ephemeral frames are broadcast but never persisted, so they never appear in .cat history or on replay. Use them for liveness signals where a missed frame does not matter.
  • time:<ms> frames expire relative to their own creation timestamp. A read never returns an expired frame, so expiry is immediate as far as any reader is concerned. A background sweeper then removes them from disk. It wakes at most once per sweep interval, xs serve --ttl-sweep, default one second, and removes a bounded batch each time, so clearing a large backlog takes several passes. No read has to touch a frame for it to be removed.
  • last:<n> schedules a per-topic garbage collection when a frame is appended to a topic already at its limit: the store keeps the n most recent frames on that topic and removes the rest. Removal is asynchronous and batched, so a topic can briefly hold more than n frames on disk, and trimming a large overflow takes several passes. Reads are unaffected — they return whatever is stored. This is retention by topic, not by frame, so it affects every frame that shares the topic.