Where Are Nemori Memories Stored? Default Filesystem Organization Explained

By default, Nemori stores all memories in a local ./memories directory using a filesystem backend, organizing episodic memories in episodes/ and semantic memories in semantic/ as per-user JSONL files.

Nemori is an open-source memory system for AI applications developed by nemori-ai. Understanding where Nemori memories are stored and how they are organized is essential for debugging, backup strategies, and custom deployments. By default, the system uses a filesystem-backed storage architecture that persists conversation history and distilled knowledge as structured JSONL files.

Default Storage Location and Configuration

Filesystem Backend Configuration

The default storage behavior is defined in src/config.py within the MemoryConfig class. When you instantiate a MemorySystem or the convenience wrapper NemoriMemory without specifying a custom backend, the system automatically selects the filesystem provider.

  • storage_path: Defaults to ./memories (relative to the project root) — see src/config.py lines 15-17
  • storage_backend: Defaults to "filesystem" — see src/config.py line 62

Base Directory Structure

Upon initialization, Nemori creates the base directory and two sub-folders for distinct memory types:


./memories/
├── episodes/
└── semantic/

This structure is established by the storage base class in src/storage/base_storage.py (lines 13-31) and the specific implementations in src/storage/episode_storage.py and src/storage/semantic_storage.py.

How Nemori Organizes Memory Files

Episodic Memory Storage

Episodic memories represent raw conversation chunks. These are stored in the episodes/ subdirectory as defined in src/storage/episode_storage.py at line 39:

super().__init__(storage_path, "episodes")

Each user receives a dedicated file following the pattern <user_id>_episodes.jsonl. Every line in this file is a JSON representation of an Episode object containing the conversation turn, timestamp, and metadata.

Semantic Memory Storage

Semantic memories contain distilled statements extracted from conversations. These reside in the semantic/ subdirectory, configured in src/storage/semantic_storage.py at lines 29-31:

self.semantic_dir = os.path.join(storage_path, "semantic")

Files follow the naming convention <user_id>_semantic.jsonl, with each line representing a SemanticMemory object containing the distilled fact, source reference, and embedding vector reference.

File Naming Conventions

Memory Type Directory File Pattern Content
Episodic episodes/ <user_id>_episodes.jsonl Raw conversation chunks
Semantic semantic/ <user_id>_semantic.jsonl Distilled knowledge statements

Memory File Format and Migration

JSONL Structure for Fast Append

Nemori uses JSONL (JSON Lines) format rather than a single large JSON file. This design choice enables:

  • Fast append operations: New memories are appended as new lines without rewriting the entire file
  • Incremental reads: The system can stream memories without loading the complete history into RAM
  • Corruption isolation: A damaged line does not invalidate the entire memory store

Each line is a self-contained JSON object representing either an Episode or SemanticMemory instance.

Backward Compatibility

Older versions of Nemori stored episodes as single JSON files (<user_id>.json). The current storage layer in src/storage/episode_storage.py automatically detects these legacy files and migrates them to the JSONL format on first read, ensuring seamless upgrades without data loss.

Working with Storage Programmatically

Initialize Nemori with Default Storage

from nemori import NemoriMemory
from nemori.src.config import MemoryConfig

# Use default configuration (filesystem storage at ./memories)

memory = NemoriMemory(config=MemoryConfig())

# Add messages for user "alice"

memory.add_messages(
    owner_id="alice",
    messages=[
        {"role": "user", "content": "What's the weather today?"},
        {"role": "assistant", "content": "It's sunny in San Francisco."},
    ],
)

# Flush to ensure writes to disk

memory.flush("alice")
memory.close()

Resulting disk structure:


./memories/
├── episodes/
│   └── alice_episodes.jsonl
└── semantic/
    └── alice_semantic.jsonl

Inspect Raw Episode Data

cat ./memories/episodes/alice_episodes.jsonl | head -n 1 | python -m json.tool
{
  "episode_id": "b2f5a1e8-3c1d-4c9a-9c6b-2a5c3e9f1b7d",
  "user_id": "alice",
  "created_at": "2026-03-08T12:34:56.789012",
  "title": "Weather query",
  "messages": [
    {"role": "user", "content": "What's the weather today?"},
    {"role": "assistant", "content": "It's sunny in San Francisco."}
  ]
}

List User Memories Without Loading Index

from nemori.src.storage.episode_storage import EpisodeStorage
from nemori.src.config import MemoryConfig

es = EpisodeStorage(MemoryConfig().storage_path)
episodes = es.list_user_items("alice")
print([e.title for e in episodes])

Delete User Data

from nemori.src.storage.episode_storage import EpisodeStorage
from nemori.src.storage.semantic_storage import SemanticStorage
from nemori.src.config import MemoryConfig

cfg = MemoryConfig()
EpisodeStorage(cfg.storage_path).delete_user_data("alice")
SemanticStorage(cfg.storage_path).delete_user_data("alice")

# Removes alice_episodes.jsonl and alice_semantic.jsonl

Summary

  • Default location: Nemori stores memories in ./memories relative to the project root, configured in src/config.py.
  • Storage backend: Filesystem backend is default (storage_backend="filesystem"), implemented in src/storage/episode_storage.py and src/storage/semantic_storage.py.
  • Directory structure: Two subdirectories organize data by type:
    • episodes/ for raw conversation chunks (<user_id>_episodes.jsonl)
    • semantic/ for distilled knowledge (<user_id>_semantic.jsonl)
  • File format: JSONL (JSON Lines) enables fast appends and streaming reads without loading entire history into memory.
  • Migration: Automatic conversion from legacy single JSON files to JSONL format ensures backward compatibility.

Frequently Asked Questions

Can I change the default storage location for Nemori memories?

Yes. The storage path is controlled by the storage_path parameter in MemoryConfig defined in src/config.py (line 15). You can instantiate NemoriMemory with a custom configuration object pointing to any accessible directory, or set the environment variable if the configuration supports it. The filesystem backend will create the episodes/ and semantic/ subdirectories at your specified location.

What is the difference between episodic and semantic memory files?

Episodic memories stored in episodes/<user_id>_episodes.jsonl contain raw conversation chunks including full message history, timestamps, and metadata for specific interaction sessions. Semantic memories stored in semantic/<user_id>_semantic.jsonl contain distilled factual statements extracted from conversations, representing consolidated knowledge rather than verbatim transcripts. The EpisodeStorage class in src/storage/episode_storage.py handles the former, while SemanticStorage in src/storage/semantic_storage.py manages the latter.

How does Nemori handle file format compatibility across versions?

Nemori uses JSONL format for all new memory storage, but maintains backward compatibility with older single JSON file formats. When EpisodeStorage encounters a legacy <user_id>.json file (without the .jsonl extension), it automatically migrates the data to the new JSONL format on first read, as implemented in the storage layer. This ensures seamless upgrades without manual data migration or loss of historical memory data.

Is it safe to manually read or backup the JSONL memory files?

Yes, the JSONL files in ./memories/episodes/ and ./memories/semantic/ are standard text files containing one JSON object per line, making them safe to read, copy, or archive using standard filesystem tools. However, you should avoid modifying files while the NemoriMemory instance is active, as the storage layer maintains in-memory buffers and indices that may become inconsistent with on-disk changes. For backups, copy the entire ./memories directory while the system is closed or use the programmatic list_user_items() methods to export data safely.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →