Session stores
Session stores persist snapshots for server-managed agents. They are the storage layer behind sessionId, snapshotId, loadChat(), snapshot reads, branching, background execution, and aborting detached work.
Use the Sessions and state guide first when you are deciding between server-managed and client-managed state. Use this page when you know the server should own state and need to choose or implement the persistence layer.
Choose a store
Section titled “Choose a store”- In-memory store (
InMemorySessionStore) for tests, local examples, command-line interfaces, and single-process experiments. - File store (
FileSessionStore) for local development, prototypes, and single-host applications where snapshots must persist across process restarts. - Firestore store (
FirestoreSessionStorefromgenkit-google-cloud) for production apps where several server instances share sessions. - Custom store (implementing
SessionStore) when you need a different shared database such as Cloud SQL, Spanner, Postgres, or Redis.
Configure the store on the agent. The runtime handles reads and writes. With HTTP serving, /getSnapshot and /abort are mounted only when a store is configured.
Use an in-memory store
Section titled “Use an in-memory store”InMemorySessionStore keeps snapshots in local process memory. It is fast and requires no setup.
from genkit.agent import InMemorySessionStore
store = InMemorySessionStore()
support_agent = ai.define_agent( name='supportAgent', model='googleai/gemini-flash-latest', system='Help customers with their orders.', store=store,)Do not use the in-memory store if session history must survive process restarts or when scaling horizontally across multiple server instances.
Use a file-backed store
Section titled “Use a file-backed store”FileSessionStore stores snapshots as JSON files inside a local directory. This is the standard choice for local development or single-host deployments.
from genkit.agent import FileSessionStore
store = FileSessionStore('.sessions')
weather_agent = ai.define_agent( name='weatherAgent', model='googleai/gemini-flash-latest', system='You help with weather questions.', store=store,)Snapshots are saved as files inside the .sessions folder.
Use a Firestore store
Section titled “Use a Firestore store”FirestoreSessionStore in genkit-google-cloud persists snapshots in Cloud Firestore. It is the built-in option for production apps where several server instances share sessions, and it supports snapshot watching for background execution and abort.
from genkit_google_cloud import FirestoreSessionStore
def by_user(context: dict | None = None) -> str: if isinstance(context, dict) and isinstance(context.get('uid'), str): return context['uid'] return 'global'
store = FirestoreSessionStore( collection='genkit-sessions', snapshot_path_prefix=by_user,)
support_agent = ai.define_agent( name='supportAgent', model='googleai/gemini-flash-latest', system='Help customers understand their order status.', store=store,)All options are optional:
clientis an explicit FirestoreAsyncClient. It defaults to a new client that picks up Application Default Credentials andFIRESTORE_EMULATOR_HOST.collectionis the collection that holds snapshot documents. It defaults togenkit-sessions. Two companion collections,<collection>-pointersand<collection>-shards, are derived from it.snapshot_path_prefixreturns a per-tenant prefix from the call context (for example an authenticated user id). When set, snapshots are nested under that prefix so one tenant cannot read another’s data even with asnapshotId. It defaults toglobal.checkpoint_intervalis the number of turns between full-state checkpoints. Between checkpoints the store writes diffs. It defaults to25.shard_sizeis the maximum size in bytes of a single shard or diff document. It defaults to 512 KiB.
The Firestore store watches snapshot documents to observe status changes, so background execution and aborts work across instances without polling. It does not prune snapshots, so plan retention for long-running or artifact-heavy conversations as described in Production guidance.
Implement a custom store
Section titled “Implement a custom store”When the built-in Firestore store does not fit, implement a custom SessionStore:
from genkit.agent import SessionSnapshot, SessionStore
class MyDatabaseSessionStore(SessionStore): async def get_snapshot( self, *, snapshot_id: str | None = None, session_id: str | None = None, context: dict | None = None, ) -> SessionSnapshot | None: # Load by snapshot_id, or resolve the latest leaf for session_id. ...
async def save_snapshot(self, snapshot_id, fn, *, context=None) -> SessionSnapshot | None: # Atomic read-modify-write: call fn(existing) and persist the result. async with self.lock: existing = await self._read(snapshot_id) updated = fn(existing) if updated is not None: await self._write(snapshot_id, updated) return updatedget_snapshotfetches a snapshot by exactsnapshot_idor resolves the latest snapshot in the sequence forsession_id.save_snapshotmust be atomic. Run the read, mutator execution, and write inside a single database transaction, or synchronize with a lock. The mutator must be side-effect free — stores may call it more than once under contention.self.lock:SessionStoreautomatically provides a loop-localasyncio.Lockviaself.lockon every store instance. You can useasync with self.lock:insidesave_snapshotto synchronize in-process read-modify-write operations without instantiating locks manually.
For detach and abort support, also implement SnapshotSubscriber so clients can poll status changes.
Production guidance
Section titled “Production guidance”- Security: Treat snapshots as sensitive user data. They can contain raw message history, tool results, and personal information. Apply authorization checks in your API or store layer before returning snapshot data.
- Payload size: Because snapshots contain full conversational checkpoints, their size grows over long sessions. Plan database indexes and cleanup/archival routines before launching production systems.