Cursor's state.vscdb is huge: what fills it, and how to shrink it
tens of gigabytes of chat state, and the way out that keeps the chats
The usual report: after a restart Cursor sits on "Loading chats", a new chat spins on the first message, and globalStorage turns out to be 30, 50 or 125 GB. Almost all of that is one file, state.vscdb, and almost all of the file is chat state.
Where it is
# macOS ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb # Linux ~/.config/Cursor/User/globalStorage/state.vscdb # Windows %APPDATA%\Cursor\User\globalStorage\state.vscdb
It is SQLite. The chats live in the cursorDiskKV table: composerData:<id> for each chat, bubbleId:<chat>:<bubble> for each message, and checkpointId: and agentKv: rows for the agent's checkpoints and blobs. The deletion page covers the layout in more detail.
Find what is big, without touching Cursor
Quit Cursor and copy the file, or read it in place with -readonly. Both queries scan the whole table, so on a 50 GB database expect a few minutes.
Which kind of row holds the space:
sqlite3 -readonly state.vscdb "
SELECT substr(key, 1, instr(key, ':') - 1) AS kind, count(*),
round(sum(length(CAST(value AS BLOB))) / 1e9, 2) AS gb
FROM cursorDiskKV GROUP BY kind ORDER BY gb DESC;"
Which chats hold it:
sqlite3 -readonly state.vscdb "
SELECT substr(key, 10, 36) AS chat, count(*) AS messages,
round(sum(length(CAST(value AS BLOB))) / 1e6) AS mb
FROM cursorDiskKV WHERE key LIKE 'bubbleId:%'
GROUP BY chat ORDER BY mb DESC LIMIT 15;"
And the name of one of them, to find it in Cursor's chat list:
sqlite3 -readonly state.vscdb " SELECT json_extract(value, '$.name') FROM cursorDiskKV WHERE key = 'composerData:<chat id>';"
The usual finding is a handful of long agent chats holding most of the file, not thousands of small ones.
Shrinking it, safest first
- Delete
state.vscdb.backup, if there is one. Cursor stopped updating it, so it is a leftover copy, sometimes over 10 GB; with Cursor quit it can go without touching a chat (Cursor staff on the forum). - Delete the biggest chats in Cursor. Export the ones you want to keep first. Deleting from the UI lets Cursor remove the rows it owns; editing the table while Cursor runs is how people lose window state along with the chat.
- Clean up after it.
Delete old chats…in the command palette removes chats in bulk, and theGC Agent KV Blobsdeveloper command removes blobs no chat refers to any more. On a database an older Cursor created, the space they free stays inside the file, so the size on disk barely moves even when Cursor gets fast again. Compaction gives it back, and needs free disk on the order of the database's size, sometimes close to twice it (62 GB for a 29 GB file). - Start over. With Cursor quit, move
state.vscdb,state.vscdb-walandstate.vscdb-shmaside, not into the trash, and start Cursor: it creates an empty database. Every chat goes from the list, and so does the other state kept there. Keep the old file until you are sure nothing in it is missed.
Keeping the chats you delete
Whichever way you shrink it, the chats in it are the record of what you worked out and what the agent ran, and Cursor keeps no archive.
deja-vu indexes Cursor's chats, reading the database through sqlite3 without writing to it, together with the history of Claude Code, Codex and the other agents on the machine. A chat that is in its index stays searchable after it leaves state.vscdb, including when the whole database is moved aside, so run it once before you delete anything:
deja index deja "pgbouncer" # finds the chat after it is gone from Cursor
In the screen bare deja opens, you can still read such a chat or press o to carry it into another agent. deja cannot write a chat back into state.vscdb. deja forget --session <id> drops one for good.
Deleting Cursor chat history · Where every agent stores history · Giving Cursor recall over the rest
Found this useful? Star deja-vu on GitHub.