Mantyl.devGuides · handing over AI-built software

Where Cursor stores your chat history

Cursor stores every chat and composer session locally, in SQLite databases inside its user data directory. The format is undocumented and has never been described by the vendor, so everything below comes from reverse-engineering real installations. We maintain an open-source Cursor adapter that reads this storage, which means we re-verify the layout regularly; this page describes the layout as observed in August 2026, and the adapter source is the executable version of it.

The short answer

The chat data lives under Cursor’s per-user data directory, in two kinds of SQLite database. The location of that directory depends on your platform:

Windows: %APPDATA%\Cursor\User
macOS: ~/Library/Application Support/Cursor/User
Linux: ~/.config/Cursor/User

Inside that directory, workspaceStorage holds one hashed folder per workspace you have opened, and globalStorage/state.vscdb holds the actual message content for every conversation across all of them. The message text you are looking for is in the global database. The per-workspace databases only hold the index that says which conversations belong to which project.

How the pieces fit together

Finding the history for one specific project takes three hops. First, each directory under workspaceStorage contains a workspace.json whose folder field is a file URI naming the project folder that workspace belongs to. On Windows the URI arrives percent-encoded, so C:\dev\my-app appears as file:///c%3A/dev/my-app, and the comparison needs to be case-insensitive. One project routinely maps to several storage directories, because Cursor creates a fresh one across certain upgrades and re-opens; if you read only the first match you will silently lose part of the history.

Second, each of those workspace directories has a state.vscdb SQLite database with a key-value table called ItemTable. The key composer.composerData holds a JSON document whose allComposers array lists every conversation in that workspace, each with a composerId, a name and a creation timestamp.

Third, the message content lives in globalStorage/state.vscdb, in a table called cursorDiskKV. Every message is one row whose key has the shape bubbleId:<composerId>:<bubbleId> and whose value is a JSON document. A type of 1 means the message is yours, 2 means it came from the model, and the prose sits in the text field alongside a createdAt timestamp. Rows that only record tool activity have an empty text field, so a transcript reconstruction needs to skip them.

Reading it yourself

Any SQLite client works. With the standard sqlite3 command line, listing a workspace’s conversations and then pulling one conversation’s messages looks like this:

sqlite3 workspaceStorage/<hash>/state.vscdb "SELECT value FROM ItemTable WHERE key = 'composer.composerData'"
sqlite3 globalStorage/state.vscdb "SELECT value FROM cursorDiskKV WHERE key LIKE 'bubbleId:<composerId>:%'"

Two practical warnings. Cursor holds these databases open while it runs, so a plain open can fail with a lock error; either open the file read-only or copy it somewhere temporary first and read the copy. And the global database grows without obvious bounds. On a machine that has used Cursor heavily for months we have seen it pass a gigabyte, so avoid tooling that tries to load it whole.

If you are scripting this in Node, the built-in node:sqlite module reads these files without any native dependency, but it needs Node 22.13 or newer.

The caveats that matter

This layout is undocumented, which means Cursor can change it in any release without notice. Treat any tool or script built on it as needing re-verification after upgrades. It also means your chat history contains everything you ever pasted into the chat, including any credentials or keys that went in during debugging. If you export or share transcripts, redact them first; the databases themselves never leave your machine unless you move them.

Deleting a conversation in Cursor’s interface does not necessarily purge the underlying rows immediately, so do not rely on the interface as a redaction tool.

Getting the history out in one run

If the reason you went looking for this storage is a handover, an audit or a record of how a project was actually built, the extraction is already automated. The Mantyl CLI finds every storage directory for a project, unions the conversations across them, skips the tool-only rows, and runs every message through secret redaction before anything is written to disk. The result feeds the decision log and claims register of a project passport, with each entry labelled by where it came from. The same run reads Claude Code and Codex CLI history alongside Cursor’s. The support matrix and troubleshooting notes are in the agents documentation.

npm install -g mantyl
mantyl scan
sessions read from Cursor, Claude Code and Codex, secrets redacted
Use cases · Docs · PricingWritten against the real product