Where state lives, and how to back it up
Everything VCode remembers is plain files under one directory,
VCODE_STATE. Copy it to back up; delete it to start clean. There is no
database.
Why you would use it
You are moving VCode to another machine, want a backup before an upgrade, or want the disk space back from a year of transcripts.
How to use it
- Find the root. Under the unit it is
~/.local/state/v-code/workbench/threads(theworkbench/directory keeps its name from before the rename); for a barenode server.jsit is~/.v-code/threads. The startup line names it:state <path>. - Back up:
tar czf v-code-state.tgz -C ~/.local/state/v-code/workbench threads. Stopping the unit first gives a clean snapshot, but the logs are append-only, so a copy taken while it runs loses at most a torn trailing line. - Restore: stop the unit, unpack in place, start it.
- Start clean: stop the unit,
rm -rfthe directory, start it. VCode recreates it empty. - Delete one thread instead: close the tab, then delete it from the UI. That is a recursive remove of the thread's own directory.
What you see
<VCODE_STATE>/
session-epoch the logout revocation timestamp
settings.json the cog's settings
tab-order.json the tab strip's order
vapid.json push keys (0600)
push-subscriptions.json subscribed devices (0600)
<thread-id>/
events.ndjson the canonical event log, one JSON object per line
raw.ndjson verbatim vendor frames
raw.1.ndjson the previous raw file, after a rotation
attachments/ files uploaded into that thread
The thread directory name is the thread id put through encodeURIComponent.
Options and settings
| Option | Default | What it changes |
|---|---|---|
VCODE_STATE |
~/.v-code/threads; $STATE_DIR/workbench/threads in the unit |
The root of everything above |
--state-dir DIR (install.sh) |
~/.local/state/v-code |
The $STATE_DIR the unit's paths are built from |
| Memory tail | 2000 events per thread | How many events stay resident; older ones are re-read from the file |
| Raw rotation | 25 MB | When raw.ndjson becomes raw.1.ndjson. Two files are kept |
Limits and known gaps
- Never rotate
vapid.json. Every installed device's push subscription is bound to that keypair. Losing it means every device has to subscribe again. Back it up with the rest. session-epochis part of the state root, so restoring an old backup restores an old revocation epoch — cookies you thought you had revoked verify again.- Deleting a thread is a hard delete: the whole directory, attachments included, goes. The route answers 409 unless the thread is closed first.
- Nothing here is encrypted. The transcripts hold whatever your agents read and
wrote, and the attachments hold whatever you uploaded.
vapid.jsonandpush-subscriptions.jsonare written 0600; the rest takes the umask. - A torn trailing write — power loss,
kill -9— is survivable: everything after the first unparseable line is discarded on read, so the log never poisons a boot. raw.ndjsonis a re-derivation source, not a replay source. Once it has rotated twice, the oldest raw frames are gone.events.ndjsonis never truncated.- Moving the state root between machines carries the threads, but not the vendor
sessions they resume from (
~/.claude/projects,~/.codex/sessions).
Related
- install-as-systemd-units — how
$STATE_DIRis chosen - environment-variables —
VCODE_STATE - sign-every-device-out — the
session-epochfile - memory-limits-and-parking — the other resource ceiling
- turn-on-notifications — the keys in
vapid.json - close-and-reopen-tabs — closing a thread before it can be deleted
- attach-photos-and-files — what lands in
attachments/ - reorder-tabs — what
tab-order.jsonholds