Skip to content

Entity History

Entity history records a entity of entity values on every create, update, and delete. This gives you a full audit trail with diffs.

Enable history in initializeRebaseBackend:

await initializeRebaseBackend({
// ...
history: true
});

Or with custom retention settings:

history: {
maxEntries: 200, // Per entity, oldest pruned first (default: 200)
ttlDays: 90 // Entries older than this are pruned (default: 90)
}

Mark which collections should track history:

import { defineCollection } from "@rebasepro/admin-types";
const ordersCollection = defineCollection({
slug: "orders",
name: "Orders",
table: "orders",
history: true, // Enable for this collection
properties: { /* ... */ }
});
  1. The backend creates a rebase.entity_history table automatically.
  2. On every create, update, or delete, a entity is recorded with:
    • Entity ID, collection slug, and table name
    • The full entity values (before and after)
    • Timestamp and user ID
    • Operation type (create, update, delete)
    • An array of changed_fields showing which columns were modified

To avoid recording redundant logs where fields are saved but no values change, the HistoryService performs a structural deep equality comparison on the top-level keys of the old and new values:

  • It ignores system metadata properties starting with __.
  • If differences are found, the names of the modified properties are saved in the changed_fields (text[]) column.
  • If the deep equality check detects zero changes, the history insertion is entirely skipped.

Unlike traditional systems that rely entirely on slow periodic batch scripts, Rebase enforces your retention policies continuously:

  • Right after a entity is saved or deleted, the server schedules an inline asynchronous sweep in a non-blocking, fire-and-forget promise.
  • This sweep immediately checks retention limits for that specific entity ID and prunes older entries exceeding maxEntries or ttlDays.
GET /api/data/:slug/:entityId/history

Returns a list of history entries for a specific entity, ordered by most recent first:

{
"data": [
{
"id": 42,
"entity_id": "123",
"collection_slug": "orders",
"operation": "update",
"values": { "status": "shipped", "total": 99.99 },
"previous_values": { "status": "pending", "total": 99.99 },
"user_id": "admin-user-id",
"created_at": "2025-01-15T10:30:00Z"
}
]
}
Setting Default Description
maxEntries 200 Maximum entries retained per individual entity ID. Oldest entries are deleted.
ttlDays 90 Entries older than this duration (in days) are deleted.
  1. Inline Pruning (Continuous): Executed asynchronously immediately after any CRUD operation. It prunes entries for the active entity using a sub-select query with an OFFSET equivalent to your maxEntries setting, deleting everything beyond that threshold.
  2. Global Pruning (Periodic): A background cleanup cron sweep (pruneExpired) runs every 6 hours to evaluate global ttlDays thresholds and clean up orphaned logs across all collections.