Cursor Chat Bulk ExportExport your Cursor chat, Composer, and Agent conversations to clean Markdown files — locally on your machine, read-only, no network uploads. Works in Visual Studio Code and Cursor (VS Code–compatible). Author: Anas Abbas · Website: anas-code.com · Publisher: AnasAbbasCode Why this extension?Cursor stores conversations in local SQLite databases under your user profile. There is no built-in “export all chats to Markdown” for a project. This extension:
Features
Requirements
Important — do not use v0.1.0Version
If you already have 0.1.0 installed
In Cursor: the extension detail page may still show The publisher may remove InstallationFrom VS Code Marketplace / Open VSX
From a
|
| Command | What it does |
|---|---|
| Export Current Workspace Chats | Discover chats for the open workspace → pick → export to .cursor-chat-export/ |
| Export All Detected Workspace Chats | Scan all workspaces in Cursor storage → pick workspace → pick chats → export |
| Open Export Folder | Reveal .cursor-chat-export/ in the file manager |
| Diagnose Current Workspace Chat Schema | Log ItemTable keys and sample values for the current workspace DB |
| Diagnose Conversation Discovery | Full discovery report (counts, DB sizes, mismatch hints); optional UI count comparison |
| Raw Discovery Mode | Inspect every discovery candidate (parsed or not) in the Output channel |
All commands are available from the Command Palette.
Export workflow (scan → pick → load → write)
Scan (fast) → QuickPick → Load messages → Write .md
metadata only your selection selected only + INDEX.md
- Scan does not load every bubble in a 2 GB database — only titles, IDs, and estimated message counts.
- Load runs per selected conversation and fetches only bubbles referenced in
composerDataheaders (not every historicalbubbleIdrow).
Progress messages:
Scanning Cursor storage…Loading chat messages… 3/10: <chat title>Exporting conversations…
Clean export vs full raw export
Clean export (recommended, default)
Produces a compact, LLM-friendly transcript:
- User and assistant text kept
- Tool-only lines removed (e.g.
`tool_…`,`call_…`) - Thinking-only placeholders removed (
**Thinking**,Thinking..., etc.) - Empty messages skipped
Good for backups, documentation, or pasting context into a new chat.
Full raw export
Includes tool calls, thinking blocks, and empty messages — useful for debugging or complete archival.
Settings
| Setting | Default | Description |
|---|---|---|
cursorChatExport.includePossibleWorkspaceMatches |
true |
Match by folder name when the full path changed (e.g. c:\wamp64\www\MyApp vs c:\laragon\www\MyApp) |
cursorChatExport.cursorUserDataPath |
"" |
Optional path to a copy of Cursor’s User folder (see below) |
Settings JSON example:
{
"cursorChatExport.includePossibleWorkspaceMatches": true,
"cursorChatExport.cursorUserDataPath": ""
}
Using a copied Cursor folder (diagnostics / migration)
If you copied %APPDATA%\Cursor\User from another PC (e.g. D:\Cursor\User) only for inspection, set:
"cursorChatExport.cursorUserDataPath": "D:\\Cursor\\User"
Or set environment variable CURSOR_APPDATA to the parent of User (the folder that contains User\globalStorage and User\workspaceStorage).
Normal export should use the live Cursor data on the machine where you run Cursor, not a stale copy — otherwise chats won’t match what you see in the UI.
Expected layout:
User/
├── globalStorage/
│ └── state.vscdb ← main DB (composerData, bubbleId); often 1–3+ GB
└── workspaceStorage/
└── <hash>/
├── workspace.json
└── state.vscdb ← per-workspace UI / panel metadata
Output format
.cursor-chat-export/
├── INDEX.md
├── diagnostics/
│ └── conversation-discovery-report.md ← after Diagnose Conversation Discovery
├── 2026-05-24__fix-login-session-error.md
├── 2026-05-24__docker-erp-setup.md
└── 2026-05-24__untitled-chat-03.md
Per-conversation file:
# Fix login session error
- **Workspace:** C:\Projects\MyApp
- **Exported at:** 2026-05-24T19:00:00.000Z
- **Original date:** 2026-05-23T14:32:11.000Z
- **Session type:** composer
- **Messages:** 28
- **Filtered internal messages:** 64
- **Source:** Cursor local chat storage
---
## User
How do I fix the session expiry bug in auth.ts?
---
## Assistant
The issue is in the `refreshToken` function…
INDEX.md lists each file with exported vs filtered counts and role breakdowns.
How discovery works (short)
Cursor splits data across:
globalStorage/state.vscdb— tablecursorDiskKV:composerData:<id>(metadata + message headers),bubbleId:<composerId>:<bubbleId>(message text).workspaceStorage/<hash>/state.vscdb— tableItemTable: UI state, includingworkbench.panel.composerChatViewPane.<tabId>whose JSON points toworkbench.panel.aichat.view.<composerId>.
The extension:
- Resolves workspace storage hashes for your folder path (and optional folder-name match).
- Collects composer IDs from workspace panel keys.
- Loads matching
composerDatafrom global storage (SQL scope + direct ID lookup). - On export, loads only bubbles listed in each composer’s headers.
Large databases (over ~2 GB)
globalStorage/state.vscdb can exceed 2 GB. Built-in sql.js cannot open files that large; the extension switches to the sqlite3 command-line tool automatically.
Windows setup
- Install SQLite (one of):
winget install SQLite.SQLite- sqlite-tools-win-x64.zip → extract
sqlite3.exe
- Either add
sqlite3to PATH, or copysqlite3.exenext to the extension bundle:- Development:
MDCursorExporter/out/sqlite3.exe - Installed:
%USERPROFILE%\.cursor\extensions\anasabbascode.cursor-chat-bulk-export-<version>\out\sqlite3.exe - Same pattern under
%USERPROFILE%\.vscode\extensions\if installed in VS Code
- Development:
Confirm in Output → Cursor Chat Bulk Export: Opened DB via cli.
Troubleshooting
Output channel
View → Output → Cursor Chat Bulk Export. Run any command; logs appear here.
UI shows more chats than export finds
Run Diagnose Conversation Discovery. Optionally enter how many chats Cursor’s UI shows (e.g. 48).
Report path: .cursor-chat-export/diagnostics/conversation-discovery-report.md
| Case | Meaning |
|---|---|
| A | Very few candidates — discovery incomplete |
| B | Many candidates, few parsed — parser gap |
| C | Many parsed, few after dedupe — duplicate IDs |
| D | Many global composers, few match workspace — path/hash filter |
| OK | Export count close to your UI hint |
Raw Discovery Mode shows each candidate key and whether it parsed.
Chat stuck on “Loading chat” in Cursor (never finishes)
That usually means no full local copy of the conversation (cloud/synced or never downloaded). The extension cannot export chats that Cursor itself cannot open. Titles may still appear in the list from workspace metadata.
Try: same account, internet, open the chat once on the old machine, wait for sync, then export again.
Export is slow
Expected for large histories:
- Scan: seconds (metadata only).
- Load: depends on selected chats; a chat with hundreds of messages may take 1–3+ minutes on a 2 GB DB.
- Write Markdown: usually seconds.
Export fewer chats at a time if needed.
No conversations found
- Run Diagnose Current Workspace Chat Schema and Diagnose Conversation Discovery.
- Ensure the correct workspace folder is open.
- On large DBs, install sqlite3 (see above).
- Set
cursorChatExport.includePossibleWorkspaceMatchestotrueif the project path moved.
Stack overflow / crash on diagnose (old versions)
Current builds use a light scan on huge DBs (counts + samples, not full key enumeration). Update to the latest VSIX if you still see Maximum call stack size exceeded.
Architecture
src/
├── extension.ts Activate / register commands
├── logger.ts Output channel logger
├── types.ts Conversation, ExportOptions, etc.
├── storage/
│ ├── cursorStorage.ts Resolve Cursor User path (APPDATA / settings)
│ ├── cursorDiskKV.ts composerData + bubbleId (header-scoped load)
│ ├── workspaceScanner.ts workspaceStorage scan + primary entry selection
│ ├── sqliteReader.ts sql.js (WASM) for smaller DBs
│ ├── sqliteCliReader.ts sqlite3 CLI for DBs ≥ ~1.85 GB
│ └── dbBackend.ts Unified DB backend (sqljs | cli)
├── workspace/
│ └── workspaceMatch.ts Path / hash / folder-name matching
├── chat/
│ ├── chatParser.ts composerData + bubbles → Conversation
│ ├── itemTableDiscovery.ts Panel keys + ChatSessionStore index
│ ├── schemaDiscovery.ts ItemTable chat key heuristics
│ └── legacyParser.ts Older ItemTable-only format
├── discovery/
│ ├── conversationDiscovery.ts Scan, defer load, hydrate for export
│ ├── discoveryReport.ts Markdown diagnostic report
│ ├── lightDbScan.ts Safe large-DB sampling
│ └── dedupeConversations.ts Merge duplicate IDs
├── export/
│ ├── exportFilter.ts Clean vs raw filtering
│ ├── markdownExporter.ts Conversation → .md
│ ├── filenameSanitizer.ts Safe Windows filenames
│ └── indexGenerator.ts INDEX.md
└── ui/
└── commands.ts Command Palette + QuickPick pipeline
Known limitations
- Undocumented Cursor schema — may change between Cursor versions; use Diagnose commands after upgrades.
- Cloud-only / NAL chats —
composerDatamay exist withisNAL: truewhile bubbles are missing locally; export shows placeholders or skips empty chats. - Chats that never load in Cursor — not recoverable from local SQLite alone.
- Performance — very large
state.vscdb+ many long chats: export can take tens of minutes; select subsets. - Workspace association — matching uses path, hash, and folder name heuristics; not 100% identical to Cursor’s UI in every edge case.
Privacy & safety
- Read-only access to Cursor databases (sql.js or sqlite3
-readonly). - No network calls; nothing is sent to third parties.
- No writes to Cursor storage; export files go only under your project’s
.cursor-chat-export/. - Existing
.mdfiles are not overwritten — a numeric suffix is added (name-2.md).
Contributing & support
- Website: anas-code.com
- Repository: github.com/anasabbasdev/cursor-chat-bulk-export
- Issues: github.com/anasabbasdev/cursor-chat-bulk-export/issues
License
MIT — Copyright (c) 2026 Anas Abbas