Field encryption
field-encryptionEncrypts app table columns and custom field values at rest with a data key per tenant, user or app, kept in Supabase Vault as bs:field-key:<owner>. Only security definer read paths that check the caller's scope decrypt; drop_field_key deletes a key so its values can no longer be read.
Database primitivesmanaged
Install
It needs no other module.
npx better-supabase add field-encryptionConfigure
The blocks entries in your config, with the default mode.
import { defineConfig } from "better-supabase/config";
export default defineConfig({
blocks: {
// Modes: "managed". The default is "managed".
"field-encryption": { mode: "managed" },
},
});Migrations
The files
npx better-supabase add field-encryption writes into your declarative schema with the default layout.Client
This block is SQL only: call its functions from your policies, RPCs and the other modules.
Events
With the outbox installed, the module writes these in the same transaction as the change.
- field_key.dropped
Dependencies
No dependencies
It installs on its own and integrates with no optional module.
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.