# Why the MCP Memory Server Uses JSONL Format: Architecture and Performance Benefits

> Discover why the MCP Memory server uses JSONL format. Learn about efficient writes, streaming reads, and backward-compatible migration from legacy JSON storage.

- Repository: [Model Context Protocol/servers](https://github.com/modelcontextprotocol/servers)
- Tags: architecture
- Published: 2026-03-01

---

**The MCP Memory server persists knowledge-graph data in JSON Lines (JSONL) format to enable efficient append-only writes, streaming-friendly reads, and seamless backward-compatible migration from legacy flat JSON storage.**

The `modelcontextprotocol/servers` repository implements a persistent knowledge graph using the **JSON Lines (JSONL)** format as its native storage protocol. According to the source code in [`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts), this line-oriented approach optimizes I/O performance for constantly growing entity-relationship graphs while preserving human readability and migration flexibility.

## Append-Only Architecture Eliminates Full-File Rewrites

The primary advantage of JSONL format is **append-only, line-oriented I/O**. In [`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts), the `saveGraph` implementation serializes each entity and relation as a self-contained JSON object, then joins the array with `"\n"` before writing【[`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts#L101)‑L116】.

This design allows the server to write new knowledge-graph records without rewriting the entire file history. Because each line represents an independent JSON object, the storage layer can efficiently grow the graph on disk using standard file-system append operations rather than serializing and flushing massive JSON arrays for every update.

## Streaming-Friendly Reads for Large-Scale Graphs

JSONL format enables **streaming-friendly reads** that minimize memory overhead. When loading data, the `loadGraph` method reads the file content, splits on newlines using `data.split("\n")`, and parses each line independently via `JSON.parse`【[`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts#L71)‑L78】.

This approach scales to very large graphs because the server never holds the raw text of the entire file in memory simultaneously. Instead, it processes the file line-by-line, keeping only the parsed objects in the working memory. This streaming paradigm prevents the memory exhaustion issues common with large monolithic JSON files.

## Backward-Compatible Migration from Legacy JSON

The server maintains **backward-compatibility** through automatic migration logic. Earlier versions stored data in a single large [`memory.json`](https://github.com/modelcontextprotocol/servers/blob/main/memory.json) file containing a JSON array. On startup, the `ensureMemoryFilePath` function detects this legacy file, renames it to `memory.jsonl`, and logs the migration【[`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts#L22)‑L39】.

This migration preserves existing user data while transitioning to the more performant JSONL format. The detection and rename operation happens automatically, ensuring that upgrades from older server versions remain seamless and non-destructive.

## Configuring the JSONL Storage Path

The JSONL file path is configurable via the `MEMORY_FILE_PATH` environment variable. The `ensureMemoryFilePath` function resolves `process.env.MEMORY_FILE_PATH` at startup, defaulting to `memory.jsonl` in the working directory【[`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts#L15)‑L20】.

The project's README explicitly documents this variable as pointing to a "JSONL file (default: `memory.jsonl`)"【[`src/memory/README.md`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/README.md#L183)‑L184】, confirming that the format is a deliberate part of the public API contract.

### Setting a Custom JSONL Path

```bash
export MEMORY_FILE_PATH=/my/data/custom-memory.jsonl
npx -y @modelcontextprotocol/server-memory

```

### Appending Entities to the JSONL File

Each entity creation appends a new JSON line to the file:

```typescript
await knowledgeGraphManager.createEntities([
  { name: "Alice", entityType: "person", observations: ["likes coffee"] },
  { name: "Bob",   entityType: "person", observations: [] }
]);

```

Resulting `memory.jsonl` content:

```text
{"type":"entity","name":"Alice","entityType":"person","observations":["likes coffee"]}
{"type":"entity","name":"Bob","entityType":"person","observations":[]}

```

### Loading and Parsing the Graph

The server reconstructs the graph by streaming the JSONL file:

```typescript
const graph = await knowledgeGraphManager.readGraph();
console.log(graph.entities.length); // → 2

```

### Automatic Migration Example

When upgrading from a legacy installation:

```bash

# Server detects old format and logs:

# DETECTED: Found legacy memory.json file, migrating to memory.jsonl for JSONL format compatibility

# COMPLETED: Successfully migrated memory.json to memory.jsonl

```

The migration logic handles the rename operation automatically【[`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts#L34)‑L38】.

## Summary

- **Line-oriented I/O**: The JSONL format in [`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts) supports efficient append operations via `saveGraph`, avoiding full-file rewrites for every entity update.
- **Streaming parser**: `loadGraph` implements line-by-line parsing using `split("\n")`, enabling large graph support without loading entire files into memory.
- **Legacy support**: The server automatically migrates from [`memory.json`](https://github.com/modelcontextprotocol/servers/blob/main/memory.json) to `memory.jsonl`, preserving data integrity across version upgrades.
- **API stability**: The `MEMORY_FILE_PATH` environment variable explicitly targets JSONL files, making the format a documented part of the server contract.

## Frequently Asked Questions

### What is the default filename for MCP Memory server storage?

The default filename is **`memory.jsonl`** in the current working directory. The `ensureMemoryFilePath` function in [`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts) returns this default when the `MEMORY_FILE_PATH` environment variable is unset【[`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts#L15)‑L20】.

### Does the MCP Memory server append to the JSONL file or rewrite it completely?

According to the source implementation, the server writes the entire graph using `saveGraph`, which joins all serialized objects with newlines【[`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts#L101)‑L116】. While the format supports append semantics, the current implementation optimizes for atomic writes by serializing the complete graph state to ensure data consistency.

### How does the server handle upgrades from the old memory.json format?

The server detects legacy [`memory.json`](https://github.com/modelcontextprotocol/servers/blob/main/memory.json) files during startup via `ensureMemoryFilePath` and automatically renames them to `memory.jsonl`【[`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts#L22)‑L39】. This migration preserves existing data while transitioning to the JSONL structure required by the current server version.

### Why is JSONL preferred over a SQLite database for this use case?

**JSONL** provides human-readable, line-oriented storage that requires no external database dependencies or binary drivers. As implemented in [`src/memory/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/memory/index.ts), the format allows simple file-based version control, easy debugging via text editors, and streaming consumption while maintaining the structural integrity required for knowledge-graph entities and relations.