Skip to content
Hoody.com

A snapshot records a container’s entire filesystem at a point in time: every file, database row, config, log, installed package, and environment file. Rather than a diff of selected paths, it is the complete disk state of the machine, frozen at a moment and restorable with one API call.

You do not decide what to include, write migration scripts, or track what changed. A button press or a single API call preserves the entire machine, and another returns it to exactly that state.


Every snapshot records the complete filesystem state of a container:

ComponentCapturedWhat it means
FilesystemFiles, directories, permission bitsCode, configs, logs, and data, exactly as they were
DatabasesData, tables, indexesSQLite files and PostgreSQL data directories, byte-identical on disk
Installed softwareapt packages, npm modules, binariesRestored at their exact versions, nothing to reinstall
EnvironmentEnvironment files, shell configs, crontabsThe on-disk runtime context is preserved
Network configDNS settings, routing table, proxy configurationOn-disk network configuration is identical after restore

If it is written to disk in the container, the snapshot captures it.


Hoody uses Copy-on-Write (CoW) at the filesystem level. When you create a snapshot, Hoody does not copy the entire disk. It marks the current filesystem state as immutable and begins tracking changes. Only new or modified blocks are stored separately.

This means:

  • Fast creation. A snapshot marks the current state rather than copying the disk, so creation cost does not grow with container size; nothing is copied or compressed.
  • Minimal storage. The first snapshot references the existing filesystem, and each later snapshot stores only the delta. Ten snapshots of a 50GB container do not cost 500GB; they cost 50GB plus the changes.
  • Frequent snapshots. The per-snapshot overhead is small enough to snapshot every commit, deployment, or experiment. Per-container snapshot caps apply (higher on rented servers than on the free tier), and expiring snapshots clean themselves up.
  • Whole-machine restore. Restoring a snapshot returns the container to the captured state exactly, in one API call, with no migration scripts and no partial state. How long it takes depends on the container.
Snapshot 1 (baseline) ──→ Full filesystem reference
Snapshot 2 (after AI) ──→ Delta: 47 files changed
Snapshot 3 (after deploy)──→ Delta: 12 files changed
Snapshot 4 (new feature) ──→ Delta: 89 files changed
Total storage: baseline + 148 files of changes
NOT: 4 full copies of the filesystem

AI generates code you cannot fully review. An LLM rewrites your authentication module: it looks correct at a glance and passes the tests you thought to write, but a subtle change in how sessions are invalidated slips past code review. Three days later you notice stale sessions. Two days after that, you trace them to the AI’s rewrite, and a week of development now sits on top of the bug.

Without a snapshot, that means reconstructing a week of changes by hand. With one, you restore before-ai-auth-rewrite, compare the two states, fix the specific issue, and move on.

Terminal window
# Before letting AI touch your code
hoody snapshots create -c $CONTAINER_ID \
--alias "before-ai-refactor"
# AI makes its changes...
# If something breaks, restore
# (use the exact `name` returned by create/list; when supplied at creation,
# the sanitized alias is that name)
hoody snapshots restore -c $CONTAINER_ID --name "before-ai-refactor"
# Back to exactly where you were

Snapshot before every AI interaction. Creating one takes seconds, and having one can save hours of debugging.


Git lets you branch code so an experiment cannot damage the main line. Snapshots bring the same workflow to the whole container.

Main state (snapshot: "production-stable")
├──→ Experiment A: try new database schema
│ Result: works. Create snapshot "with-new-schema"
├──→ Experiment B: try different AI model
│ Result: failed. Restore to "production-stable"
└──→ Experiment C: try new auth system
Result: promising. Create snapshot "auth-v2-wip"

Everything happens on the same container, with nothing to clone, provision, or wait for. You are not creating new machines; you are recording states of one machine and moving between them.

Terminal window
# Save the current state
hoody snapshots create -c $CONTAINER_ID --alias "main-branch"
# Experiment: try a risky database migration
hoody terminal sessions exec -c $CONTAINER_ID \
--command "python3 migrate.py --destructive"
# If it worked: save the result
hoody snapshots create -c $CONTAINER_ID --alias "after-migration"
# If it failed: restore and try something else (use the exact `name` returned by create/list)
hoody snapshots restore -c $CONTAINER_ID --name "main-branch"

Snapshots turn deployments into reversible operations. Capture the state before you deploy, verify the result, and restore if verification fails.

1. Snapshot: POST /api/v1/containers/{prod}/snapshots
{"alias": "pre-deploy-v2.1.0", "expiry": 30}
2. Deploy: Execute your deployment scripts
3. Verify: Health checks, smoke tests, monitoring
4. Success: Delete the snapshot after 30 days (or let it expire)
5. Failure: PUT /api/v1/containers/{prod}/snapshots/pre-deploy-v210
(the exact `name` from the step 1 response; the alias is
sanitized to `[a-zA-Z0-9_-]`, so the dots are stripped)
Production restored to the pre-deploy state

A restore does not mean rolling back the code, re-running migrations, and hoping the data is consistent. It rolls back everything at once, in one API call: code, config, data, installed packages, the entire disk state.

Terminal window
# Before deployment
hoody snapshots create -c $PROD_CONTAINER \
--alias "pre-deploy-v2.1.0" \
--expiry 30
# Deploy
hoody terminal sessions exec -c $PROD_CONTAINER \
--command "./deploy.sh v2.1.0"
# Verify
hoody terminal sessions exec -c $PROD_CONTAINER \
--command "curl -s localhost:3000/health | jq .status"
# If failed: roll back (use the exact `name` from the create output;
# the alias is sanitized, so "pre-deploy-v2.1.0" lands as "pre-deploy-v210")
hoody snapshots restore -c $PROD_CONTAINER --name "pre-deploy-v210"

Something broke, but you are not sure when. With snapshots at regular intervals, you can binary-search for the change:

Monday snapshot: working
Tuesday snapshot: working
Wednesday snapshot: BROKEN

Restore Tuesday’s snapshot and confirm it still works: the bug was introduced between Tuesday and Wednesday. If you keep hourly snapshots, narrow the window to an hour, then compare the two states to find the exact change.

The bug might be in a config file, an environment variable, a system package update, or a cron job that ran at 3 AM. Everything on disk is in the snapshot, so the search covers the whole machine rather than only the source tree.


Terminal window
# Create with alias
hoody snapshots create -c $CONTAINER_ID --alias "milestone-v1"
# Create with expiration (auto-delete after 7 days)
hoody snapshots create -c $CONTAINER_ID \
--alias "temp-experiment" \
--expiry 7
# Create permanent snapshot (no expiration)
hoody snapshots create -c $CONTAINER_ID \
--alias "golden-image"
Terminal window
# List all snapshots for a container
hoody snapshots list -c $CONTAINER_ID
Terminal window
# Restore from a snapshot (use the exact `name` returned by create/list)
hoody snapshots restore -c $CONTAINER_ID --name "milestone-v1"
Terminal window
# Delete a snapshot to free storage
hoody snapshots delete -c $CONTAINER_ID --name "milestone-v1"

Snapshot before every AI task and set the expiry to 7 days. If the AI’s changes survive a week of use, the snapshot deletes itself. If something surfaces before then, you have the week to catch it.

Terminal window
# Alias pattern: before-ai-{task}-{date}
POST /api/v1/containers/{id}/snapshots
{"alias": "before-ai-auth-rewrite-2026-03-04", "expiry": 7}

Snapshot before and after every deployment. Keep the “before” for 30 days (rollback window). Keep the “after” permanently if the version is a major release.

Terminal window
# Before deploy: temporary
{"alias": "pre-deploy-v2.1.0", "expiry": 30}
# After deploy (major version): permanent
{"alias": "v2.0.0-stable"}

Use cron or hoody-cron to snapshot every container daily. Set expiry to 30 days. You always have a month of daily restore points, and old snapshots clean themselves up.

Set up a development environment once and snapshot it permanently. When a new team member joins, copy the container from that snapshot. One golden image produces as many copies as you need.

Terminal window
# The golden image: never expires
{"alias": "dev-template-2026-q1"}
# New team member:
POST /api/v1/containers/{template}/copy
{"target_project_id": "...", "name": "alice-dev", "source_snapshot": "dev-template-2026-q1"}

When a container is compromised:

  1. Snapshot the compromised state for forensic analysis
  2. Restore the last known-good snapshot so production runs from a clean state
  3. Compare the two snapshots to identify exactly what changed: which files were modified, which processes were added, what data was exfiltrated
  4. Delete the compromised snapshot after analysis

You lose neither the evidence nor the uptime: the attacker’s changes stay in a snapshot for later study while production keeps serving from a clean state. The whole sequence is a handful of API calls.


Git versions code. Snapshots version everything else.

GitSnapshots
Source codeYesYes
Database stateNoYes
System configurationPartially (dotfiles)Yes (all of /etc)
Installed packagesNo (requires rebuild)Yes (exact binary state)
Environment filesNo (.env in .gitignore)Yes
On-disk app/browser dataNoYes
Network configurationNoYes
RestoreRebuild (clone + install + build + migrate)One API call

Git versions what you wrote and snapshots version what you run; together they cover the entire stack.


Next: Realms & Projects explains how containers are organized.