Field history
field-historyThe old and new value of chosen columns of any registered record on every update, who changed it and when, read per record and field.
Database primitivesmanaged
Install
The command also installs updated-at, tenant, access, subjects, the modules it needs.
npx better-supabase add field-historyConfigure
The blocks entries in your config, with the default mode.
import { defineConfig } from "better-supabase/config";
export default defineConfig({
blocks: {
// Required by field-history; add installs them too.
"updated-at": {},
tenant: {},
access: {},
subjects: {},
// Modes: "managed". The default is "managed".
"field-history": { mode: "managed" },
},
});Migrations
The files
npx better-supabase add field-history writes into your declarative schema with the default layout.Client
This block has no React entry yet. Its TypeScript side is in better-supabase/blocks/field-history, which runs on the server.
Events
With the outbox installed, the module writes these in the same transaction as the change.
This module writes no outbox events.
Dependencies
Recipes
No UI recipe uses it yet. See all recipes.
More in Database primitives
- Update timestampsupdated-atKeeps an updated_at column current on every update.
- Realtime table changesrealtime-tablesBroadcasts a change signal (no row data) once per statement on bs:t:<schema>.<table>[:<tenant>], or bs:t:<schema>.<table>:u:<user> for realtime.users tables, for live queries.
- JSON Schema checks for jsonbjsonb-schemaspg_jsonschema check constraints for jsonb columns with a `schema` in the `json` config, so the database enforces the same shape as the types. A trigger reports what failed through jsonschema_validation_errors, which the client maps to a validation error.
- pgTAP helperspgtaptests.create_user, tests.authenticate_as and catalog checks (every_table_has_rls, policies_use, no_anon_policies, every_table_audited, partitions_have_rls) for `supabase test db`. Written to supabase/tests, never to your schema.
- Read setsread-setsOne `stable` function per `defineReadSet` in `readSets`, so `db.$many(readSet, params)` is a single GET.
- Number sequencesnumber-sequencesGapless numbers per tenant, entity and period. next_number locks the row in the caller's transaction, and a trigger fills the document column so a separate round trip cannot open a gap.