About filesystem snapshotting
Filesystem snapshotting lets you read your Base as it existed at any point in the past. When enabled, Exabase continuously records the state of every resource and space, so you can retrieve historical data, compare versions, or restore a Base to an earlier point in time.
Filesystem snapshotting is available on all paid plans at no additional cost.
How it works
Every write to a resource or space is captured into history tables. The granularity is one hour – multiple changes to the same resource within a single hour collapse into a single record rather than creating new rows. When you query with a snapshotAt timestamp, the API returns the state that was current at that moment.
Filesystem snapshotting captures resource and space metadata: name, description, kind, icon, location, deletion state, and more. It does not capture operational fields (indexing state, deduplication keys) or the actual file content – only the resource attributes.
Resources moved to the bin are soft-deleted and remain discoverable and recoverable via snapshots, or direct recovery from the bin. After 30 days in the bin they are hard-deleted and the file is permanently removed. Once hard-deleted, a resource cannot be recovered by restoring a snapshot containing it.
Aging policy
As history ages, it is automatically compacted into coarser time windows to keep storage bounded:
| Age of record | Granularity |
|---|---|
| 0 – 24 hours | 1 hour |
| 1 – 7 days | 6 hours |
For example, querying a timestamp from yesterday will resolve to whichever 6-hour window it falls in, not the exact hour. Records older than 7 days are pruned automatically.
Querying a snapshotAt timestamp older than 7 days will return no historical data for affected resources.
Enabling filesystem snapshotting
Filesystem snapshotting is disabled by default. Enable it per Base via the settings endpoint.
Endpoint: PATCH /v2/snapshots/settings
import { Exabase } from "@exabase/sdk";
const api = new Exabase({
apiKey: process.env.EXABASE_API_KEY,
});
await api.resourceHistory.patchSettings({ enabled: true });
curl https://api.exabase.io/v2/snapshots/settings \
-X PATCH \
-H 'X-Api-Key: <EXABASE_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{ "enabled": true }'
History capture begins immediately once enabled. However, resources that existed before enabling will only have their state recorded on their next update – there is no backfill of prior state.
Disabling filesystem snapshotting
Set enabled to false in the same endpoint.
import { Exabase } from "@exabase/sdk";
const api = new Exabase({
apiKey: process.env.EXABASE_API_KEY,
});
await api.resourceHistory.patchSettings({ enabled: false });
curl https://api.exabase.io/v2/snapshots/settings \
-X PATCH \
-H 'X-Api-Key: <EXABASE_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{ "enabled": false }'
Existing history is preserved until it ages out of the retention window.
Querying snapshots
Pass a snapshotAt timestamp to any supported endpoint to retrieve the state at that point in time. The API returns the historical state, including resources that have since been deleted.
There are two ways to specify the timestamp:
snapshotAtparameter: pass an ISO 8601 timestamp as a query parameter or body field on any supported endpoint.X-Snapshot-Atheader: pass the timestamp as a request header. The header takes priority when both are present.
The timestamp must be in the past. Future values are rejected.
Get a resource at a point in time
Endpoint: GET /v2/resources/{resourceId}
import { Exabase } from "@exabase/sdk";
const api = new Exabase({
apiKey: process.env.EXABASE_API_KEY,
});
const resource = await api.resources.get({
resourceId: 'c99c57c3-34f5-4fde-a678-f9815cd99db5',
snapshotAt: new Date('2025-03-01T12:00:00.000Z'),
});
curl 'https://api.exabase.io/v2/resources/c99c57c3-34f5-4fde-a678-f9815cd99db5?snapshotAt=2025-03-01T12:00:00.000Z' \
-H 'X-Api-Key: <EXABASE_API_KEY>'
# or using the header
curl https://api.exabase.io/v2/resources/c99c57c3-34f5-4fde-a678-f9815cd99db5 \
-H 'X-Api-Key: <EXABASE_API_KEY>' \
-H 'X-Snapshot-At: 2025-03-01T12:00:00.000Z'
Filter resources at a point in time
Endpoint: POST /v2/resources/filter
import { Exabase } from "@exabase/sdk";
const api = new Exabase({
apiKey: process.env.EXABASE_API_KEY,
});
const results = await api.resources.filter({
parentId: 'c99c57c3-34f5-4fde-a678-f9815cd99db5',
snapshotAt: new Date('2025-03-01T12:00:00.000Z'),
});
curl https://api.exabase.io/v2/resources/filter \
-X POST \
-H 'X-Api-Key: <EXABASE_API_KEY>' \
-H 'X-Snapshot-At: "2025-03-01T12:00:00.000Z"' \
-H 'Content-Type: application/json' \
-d '{
"parentId": "c99c57c3-34f5-4fde-a678-f9815cd99db5"
}'
Retention
By default, history follows the aging policy above (7 days max). You can set a shorter retentionDays value to discard history earlier.
import { Exabase } from "@exabase/sdk";
const api = new Exabase({
apiKey: process.env.EXABASE_API_KEY,
});
await api.resourceHistory.patchSettings({ enabled: true, retentionDays: 3 });
curl https://api.exabase.io/v2/snapshots/settings \
-X PATCH \
-H 'X-Api-Key: <EXABASE_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{ "enabled": true, "retentionDays": 3 }'
Checking current settings
Endpoint: GET /v2/snapshots/settings
import { Exabase } from "@exabase/sdk";
const api = new Exabase({
apiKey: process.env.EXABASE_API_KEY,
});
const settings = await api.resourceHistory.getSettings();
// { enabled: true, enabledAt: '2025-01-15T09:00:00.000Z', retentionDays: 7 }
curl https://api.exabase.io/v2/snapshots/settings \
-H 'X-Api-Key: <EXABASE_API_KEY>'