Skip to content

Memory Storage

The @graphrag-js/memory package provides in-memory and file-based storage for development, testing, and small-scale production use.

Installation

bash
pnpm add @graphrag-js/memory

The memory package is included by default with @graphrag-js/core.

Features

  • Zero external dependencies - No database required
  • Fast performance - Sub-millisecond operations
  • File persistence - Optional JSON file storage
  • Simple setup - Perfect for development and testing
  • Full feature support - Implements all storage interfaces

Storage Options

In-Memory Storage

All data stored in RAM. Fast but not persistent across restarts.

typescript
import { createGraph } from '@graphrag-js/core';
import { memoryGraph, memoryVector, memoryKV } from '@graphrag-js/memory';
import { openai } from '@ai-sdk/openai';

const graph = createGraph({
  model: openai('gpt-4o-mini'),
  embedding: openai.embedding('text-embedding-3-small'),
  storage: {
    graph: memoryGraph,
    vector: memoryVector,
    kv: memoryKV,
  }
});

File-Based Storage (Persistent)

Data persists to JSON files on disk.

typescript
import { jsonGraph, jsonKV, memoryVector } from '@graphrag-js/memory';

const graph = createGraph({
  model: openai('gpt-4o-mini'),
  embedding: openai.embedding('text-embedding-3-small'),
  storage: {
    graph: jsonGraph('./data/graph.json'),
    vector: memoryVector, // No file persistence for vectors yet
    kv: jsonKV('./data/kv.json'),
  }
});

API Reference

memoryGraph(namespace)

Creates an in-memory graph store using Cytoscape.js.

typescript
import { memoryGraph } from '@graphrag-js/memory';

const graphStore = memoryGraph('my-namespace');

Features:

  • Node and edge CRUD operations
  • Connected components clustering
  • BFS/DFS traversal
  • Knowledge graph extraction
  • Cytoscape.js algorithms

Implementation: Uses Cytoscape.js headless mode for graph operations.

memoryVector(namespace)

Creates an in-memory vector store with cosine similarity search.

typescript
import { memoryVector } from '@graphrag-js/memory';

const vectorStore = memoryVector('my-namespace');

Features:

  • Multiple distance metrics (cosine, euclidean, dotproduct)
  • Metadata filtering
  • Index management
  • In-memory CRUD operations

Implementation: Pure TypeScript implementation with manual similarity calculations.

memoryKV(namespace)

Creates an in-memory key-value store using JavaScript Map.

typescript
import { memoryKV } from '@graphrag-js/memory';

const kvStore = memoryKV('my-namespace');

Features:

  • Fast lookups (O(1))
  • Field filtering
  • Batch operations
  • Simple Map-based storage

Implementation: JavaScript Map with JSON serialization support.

jsonGraph(filepath)

Creates a file-persisted graph store.

typescript
import { jsonGraph } from '@graphrag-js/memory';

const graphStore = jsonGraph('./data/graph.json');

Features:

  • Automatic file persistence
  • GraphML export/import
  • Same API as memoryGraph
  • Load on startup, save on changes

File Format: GraphML (XML-based graph format)

jsonKV(filepath)

Creates a file-persisted key-value store.

typescript
import { jsonKV } from '@graphrag-js/memory';

const kvStore = jsonKV('./data/kv.json');

Features:

  • Automatic file persistence
  • JSON format
  • Same API as memoryKV
  • Load on startup, save on changes

File Format: JSON

Usage Examples

Basic Setup

typescript
import { createGraph } from '@graphrag-js/core';
import { similarityGraph } from '@graphrag-js/similarity';
import { memoryGraph, memoryVector, memoryKV } from '@graphrag-js/memory';
import { openai } from '@ai-sdk/openai';

const graph = createGraph({
  model: openai('gpt-4o-mini'),
  embedding: openai.embedding('text-embedding-3-small'),
  provider: similarityGraph(),
  storage: {
    graph: memoryGraph,
    vector: memoryVector,
    kv: memoryKV,
  }
});

await graph.insert('Your documents here...');
const result = await graph.query('Your question?');

With File Persistence

typescript
import { jsonGraph, jsonKV, memoryVector } from '@graphrag-js/memory';

const graph = createGraph({
  model: openai('gpt-4o-mini'),
  embedding: openai.embedding('text-embedding-3-small'),
  storage: {
    graph: jsonGraph('./data/graph.graphml'),
    vector: memoryVector, // Still in-memory
    kv: jsonKV('./data/chunks.json'),
  }
});

Multi-Tenant Setup

typescript
const tenant1 = createGraph({
  namespace: 'tenant-1',
  storage: {
    graph: memoryGraph,
    vector: memoryVector,
    kv: memoryKV,
  }
});

const tenant2 = createGraph({
  namespace: 'tenant-2',
  storage: {
    graph: memoryGraph,
    vector: memoryVector,
    kv: memoryKV,
  }
});

// Completely isolated storage

Performance

Benchmarks

Operations on 10,000 nodes/vectors (M1 Mac):

OperationmemoryGraphmemoryVectormemoryKV
Insert0.1ms0.05ms0.01ms
Lookup0.05ms-0.01ms
Vector Search (k=10)-2-5ms-
Graph Traversal (depth=2)1-3ms--

Memory Usage

Approximate memory usage:

  • Graph Node: ~1KB per node
  • Vector (1536-dim): ~6KB per vector
  • KV Entry: ~0.5-2KB per entry (depends on content)

Example: 10,000 documents with entities:

  • ~50,000 nodes × 1KB = 50MB
  • ~10,000 vectors × 6KB = 60MB
  • ~10,000 chunks × 1.5KB = 15MB
  • Total: ~125MB

Limitations

When to Use Memory Storage

Good for:

  • Development and testing
  • Prototyping and demos
  • Small datasets (< 100K documents)
  • Single-server deployments
  • Fast iteration cycles

Not recommended for:

  • Large-scale production (> 100K documents)
  • Distributed systems
  • High-availability requirements
  • Long-running processes with large datasets
  • When you need advanced graph algorithms (use Neo4j)

Memory Limits

JavaScript has a default heap size limit:

  • Node.js default: ~2GB (32-bit) or ~4GB (64-bit)
  • Can increase with --max-old-space-size flag
bash
node --max-old-space-size=8192 your-app.js  # 8GB heap

Migration to Production

When you outgrow memory storage, migrate to production backends:

typescript
// Step 1: Export from memory
const memoryGraph = createGraph({
  storage: { graph: memoryGraph, vector: memoryVector, kv: memoryKV }
});

const data = await memoryGraph.export('json');

// Step 2: Create production graph
import { neo4jGraph } from '@graphrag-js/neo4j';
import { qdrantVector } from '@graphrag-js/qdrant';
import { redisKV } from '@graphrag-js/redis';

const prodGraph = createGraph({
  storage: {
    graph: neo4jGraph({ url: 'bolt://localhost:7687', ... }),
    vector: qdrantVector({ url: 'http://localhost:6333', ... }),
    kv: redisKV({ host: 'localhost', port: 6379 })
  }
});

// Step 3: Import data
await prodGraph.import(data);

Best Practices

Development Workflow

  1. Use memory storage during development for fast iteration
  2. Add file persistence for local testing
  3. Switch to production storage for deployment

Testing Strategy

typescript
// test/setup.ts
export function createTestGraph() {
  return createGraph({
    namespace: `test-${Date.now()}`, // Unique per test
    storage: {
      graph: memoryGraph,
      vector: memoryVector,
      kv: memoryKV,
    }
  });
}

// test/my-feature.test.ts
describe('My Feature', () => {
  it('should work', async () => {
    const graph = createTestGraph();
    // Test with clean, isolated storage
  });
});

Backup Strategy

For file-based storage:

typescript
import { jsonGraph, jsonKV } from '@graphrag-js/memory';
import { cpSync } from 'fs';

// Periodic backups
setInterval(() => {
  cpSync('./data/graph.json', `./backups/graph-${Date.now()}.json`);
  cpSync('./data/kv.json', `./backups/kv-${Date.now()}.json`);
}, 3600000); // Every hour

Next Steps

Released under the Elastic License 2.0.