Skip to content

Data Stores

AutoMem uses two specialized databases that serve complementary purposes:

  • FalkorDB (required): Graph database storing Memory nodes, relationships, and metadata. Acts as the source of truth.
  • Qdrant (optional): Vector database storing dense embeddings for semantic similarity search. Enhances performance but is not required for operation.

The system is designed for graceful degradation: all core functionality continues if Qdrant is unavailable, with the API falling back to keyword-based search in FalkorDB.


graph TB
    subgraph api["Flask API Layer"]
        StoreMemory["POST /memory<br/>app.py:~467-600"]
        RecallMemory["GET /recall<br/>app.py:~602-900"]
        UpdateMemory["PATCH /memory/:id<br/>app.py:~902-1000"]
    end

    subgraph canonical["Canonical Storage FalkorDB"]
        GraphDB[("FalkorDB<br/>FALKORDB_HOST:FALKORDB_PORT")]

        subgraph nodes["Node Types"]
            MemoryNode["Memory nodes<br/>Properties: id, content,<br/>tags, importance,<br/>timestamp, type,<br/>confidence"]
            PatternNode["Pattern nodes<br/>Shared patterns<br/>across memories"]
            EntityNode["Entity nodes<br/>People, tools,<br/>projects, concepts"]
        end

        subgraph edges["Relationship Types"]
            RelTypes["RELATES_TO<br/>LEADS_TO<br/>OCCURRED_BEFORE<br/>PREFERS_OVER<br/>EXEMPLIFIES<br/>CONTRADICTS<br/>REINFORCES<br/>INVALIDATED_BY<br/>EVOLVED_INTO<br/>DERIVED_FROM<br/>PART_OF"]
        end
    end

    subgraph optional["Optional Vector Search Qdrant"]
        VectorDB[("Qdrant<br/>QDRANT_URL")]
        Collection["Collection: COLLECTION_NAME<br/>Dimensions: VECTOR_SIZE<br/>Distance: Cosine"]
        Payload["Payload:<br/>Full memory properties<br/>for filtering"]
    end

    StoreMemory -->|"1. Always succeeds"| GraphDB
    StoreMemory -.->|"2. Best-effort"| VectorDB

    RecallMemory -->|"1. Keyword/Graph search"| GraphDB
    RecallMemory -.->|"2. Semantic search<br/>if available"| VectorDB

    UpdateMemory -->|"1. Update canonical"| GraphDB
    UpdateMemory -.->|"2. Update vector<br/>if content changed"| VectorDB

    GraphDB --- MemoryNode
    GraphDB --- PatternNode
    GraphDB --- EntityNode
    GraphDB --- RelTypes

    VectorDB --- Collection
    Collection --- Payload

FalkorDB is a Redis-compatible graph database that stores memories as nodes with typed relationships. It serves as the authoritative data store and enables:

  • Node storage: Each memory is a Memory node with properties (content, type, importance, confidence, timestamp, tags)
  • Relationship traversal: 11 relationship types connect memories semantically (see Relationship Types)
  • Keyword search: Cypher queries perform content/tag matching
  • Temporal queries: Filter memories by timestamp ranges
  • Pattern detection: Store and query recurring patterns via enrichment metadata
Environment VariableDefaultDescription
FALKORDB_HOSTlocalhostHostname or IP address
FALKORDB_PORT6379Redis protocol port
FALKORDB_PASSWORD(none)Authentication password
FALKORDB_GRAPHmemoriesGraph database name

Connection Initialization: The Flask app establishes the connection at startup via init_db_connections() (app.py:77-78).

FalkorDB uses Redis AOF (Append-Only File) and RDB snapshots for durability. Configuration via REDIS_ARGS:

  • --save 60 1: Snapshot if 1 or more keys change in 60 seconds
  • --appendonly yes: Enable AOF persistence
  • --appendfsync everysec: Fsync AOF every second (balance safety/performance)
  • --requirepass: Require authentication

Memory Node Creation

Memories are created via MERGE to ensure idempotency (app.py:2155-2185).

Relationship Creation

The /associate endpoint creates typed edges between memory nodes (app.py:2660-2750).

Keyword Search

The _graph_keyword_search function performs content and tag matching using Cypher queries (app.py:721-829).


Qdrant stores dense vector embeddings and enables semantic similarity search via cosine distance. It provides:

  • Fast vector search: Sub-100ms similarity queries over thousands of memories
  • Payload mirroring: Stores memory content, tags, importance alongside vectors
  • Filtered search: Combine vector similarity with tag/metadata filters
  • Batch operations: Efficient bulk upserts for embedding generation
Environment VariableDefaultDescription
QDRANT_URL(none)Full URL (e.g., https://xyz.cloud.qdrant.io)
QDRANT_API_KEY(none)API key for authentication
QDRANT_COLLECTIONmemoriesCollection name
VECTOR_SIZE3072Embedding dimensions (must match collection and provider)

Dimension Validation

AutoMem validates vector dimensions against the configured VECTOR_SIZE before writing to Qdrant. Mismatches raise a ValueError with a clear message, preventing Qdrant collection corruption from mixed dimensions (automem/utils/validation.py).

AutoMem uses a provider-based embedding system with automatic fallback. The default provider is OpenAI’s text-embedding-3-large model (3072 dimensions).

Provider Selection Priority (Auto Mode):

  1. Voyage AI (if VOYAGE_API_KEY set)
  2. OpenAI (if OPENAI_API_KEY set)
  3. FastEmbed (local ONNX, if installed)
  4. Ollama (local server, if running)
  5. Placeholder (hash-based, always available)

Provider Features:

ProviderDimensionsRequires NetworkCostSemantic Quality
Voyage1024, 2048YesPaid APIExcellent
OpenAI768, 3072YesPaid APIExcellent
OllamaConfigurableLocalFreeGood
FastEmbed384, 768, 1024No (after download)FreeGood
PlaceholderConfigurableNoFreeNone (hash-based)

Embedding Configuration:

Environment VariableDefaultDescription
EMBEDDING_PROVIDERautoProvider selection: auto, voyage, openai, ollama, local, placeholder
VECTOR_SIZE3072Embedding dimensions (must match Qdrant collection)
EMBEDDING_MODELtext-embedding-3-largeModel identifier for provider
VOYAGE_API_KEY(none)Voyage AI API key
VOYAGE_MODELvoyage-4Voyage model selection
OPENAI_API_KEY(none)OpenAI or compatible API key
OPENAI_BASE_URL(none)Custom endpoint for OpenAI-compatible providers
OLLAMA_BASE_URL(none)Ollama server endpoint
OLLAMA_MODEL(none)Ollama embedding model
EMBEDDING_BATCH_SIZE20Max items per batch
EMBEDDING_BATCH_TIMEOUT_SECONDS2.0Max wait before processing batch

The _vector_search function performs similarity queries against the Qdrant collection (app.py:924-994).


Every memory write performs dual storage to maintain consistency:

  1. Write to FalkorDB (always committed, synchronous)
  2. Queue embedding generation (asynchronous, background worker)
  3. Write embedding to Qdrant (best-effort, async — failure is logged, not propagated)

The /recall endpoint combines results from both databases:

  1. If Qdrant is available: execute vector similarity search
  2. Execute FalkorDB keyword/graph search
  3. Merge results using deduplication (seen_ids set)
  4. Apply 9-component hybrid scoring
  5. Sort and return top results

For details on the scoring formula, see Hybrid Search.


AutoMem is designed to continue operating if Qdrant is unavailable or misconfigured.

Write Operations (Qdrant Unavailable):

  • Memory writes to FalkorDB succeed normally
  • Embedding generation jobs are queued but not stored
  • Memories remain fully accessible via keyword search
  • No error is returned to clients

Read Operations (Qdrant Unavailable):

  • Vector similarity search is skipped
  • Results come entirely from FalkorDB keyword search
  • Relationship traversal still works (graph-based)
  • Search quality degrades but remains functional

The /health endpoint reports both database states:

DatabaseStatesMeaning
FalkorDBconnected, errorAlways required, error halts startup
Qdrantconnected, not_configured, errorOptional, errors logged but not fatal

In production, FalkorDB requires a persistent volume.

Railway Volume Configuration: Mount path stores:

  • RDB snapshots: Point-in-time backups triggered by --save rules
  • AOF log: Append-only file of all write operations
  • Graph data: FalkorDB’s internal graph structures

Qdrant Cloud handles persistence automatically. For self-hosted Qdrant, configure a volume at /qdrant/storage.


The Flask app maintains a single persistent connection. FalkorDB uses Redis pipelining internally for efficiency. No explicit pooling is required for single-threaded Flask.

The Qdrant client maintains HTTP/2 connection pooling automatically via httpx.


FeatureFalkorDBQdrant
RoleSource of truthPerformance enhancement
RequiredYesNo (optional)
Data StructureGraph (nodes + edges)Vectors + payloads
Primary UseRelationships, metadata, keywordsSemantic similarity
Query LanguageCypherVector search API
PersistenceAOF + RDB snapshotsAutomatic (cloud) or volume
Port6379 (Redis protocol)6333 (HTTP)
Typical Latency5-20ms (keyword)50-100ms (vector)
Failure ImpactService haltsDegrades to keyword search
Default DimensionsN/A3072 (configurable: 384, 768, 1024, 2048, 3072)
Embedding ProvidersN/AVoyage, OpenAI, Ollama, FastEmbed, Placeholder