Memory Backends

All backends implement the same MemoryService trait, so you choose one by enabling a feature flag and constructing it — your agent code doesn't change. There are six.

At a glance

BackendFeaturePersistenceSearchUse when
InMemoryMemoryService(default)Process onlyKeywordDevelopment, tests, demos
SqliteMemoryServicesqlite-memoryA fileKeywordSingle-node apps, local persistence
PostgresMemoryServicedatabase-memoryPostgres + pgvectorVector similarityProduction semantic search
RedisMemoryServiceredis-memoryRedis (optional TTL)KeywordFast, ephemeral-ish, shared cache
MongoMemoryServicemongodb-memoryMongoDBKeyword / vectorExisting Mongo infra
Neo4jMemoryServiceneo4j-memoryNeo4jGraphExisting Neo4j infra

(The bi-temporal GraphMemoryService is a seventh, covered on its own page — Knowledge graph.)

InMemory — start here

Zero setup. Everything lives in the process and disappears on exit.

use adk_memory::InMemoryMemoryService;
let memory = InMemoryMemoryService::new();

Perfect for development and the test suite; swap it for a durable backend with a one-line change because the trait is identical.

SQLite — a file

Durable, single-file, no server. Great for desktop apps and single-node services.

use adk_memory::SqliteMemoryService;
let memory = SqliteMemoryService::new("sqlite://memory.db").await?;
// or build from an existing pool: SqliteMemoryService::from_pool(pool)

The backend for real similarity search. It stores embeddings in pgvector and lets you pick the index strategy.

use adk_memory::{PostgresMemoryService, VectorIndexType};

let memory = PostgresMemoryService::builder(pool, embedding_provider)
    .vector_index(VectorIndexType::Hnsw { m: 32, ef_construction: 128 })  // or IvfFlat / None
    .build()
    .await?;

VectorIndexType::None does exact (brute-force) search — fine for small sets; Hnsw (the default) and IvfFlat scale to large ones. Vector search needs an embedding provider.

Redis, MongoDB, Neo4j

Use these when you already run the infrastructure:

use adk_memory::{RedisMemoryService, RedisMemoryConfig};
use std::time::Duration;

let memory = RedisMemoryService::new(RedisMemoryConfig {
    url: "redis://localhost:6379".into(),
    ttl: Some(Duration::from_secs(60 * 60 * 24 * 30)),   // optional expiry
}).await?;

MongoMemoryService::new(...) and Neo4jMemoryService::new(...) follow the same shape. All of them honor the (app, user, project) isolation from Concepts.

Embeddings

Backends that do vector similarity (Postgres, optionally Mongo) need to turn text into vectors. Provide an EmbeddingProvider:

#[async_trait]
pub trait EmbeddingProvider: Send + Sync {
    async fn embed(&self, texts: &[String]) -> Result<Vec<Vec<f32>>>;
}

Keyword backends (InMemory, SQLite, Redis) don't need one. Match the embedding model you index with the one you query with.

Migrations

The SQL-backed services run versioned, idempotent migrations to create and upgrade their schema, so deploying a new version doesn't require manual DDL. Call the service's migrate() (or let construction handle it) on startup.

Choosing

  • Building / testing → InMemory.
  • One node, want it to persist → SQLite.
  • Real semantic recall at scale → Postgres + pgvector.
  • You already run Redis / Mongo / Neo4j → that backend.
  • You want a queryable model of the user, not a transcriptGraphMemoryService.

Next: Knowledge graph →