Skip to content

no-database-functions

Prefer explicit application behavior to stored SQL functions.

Why

Under a single-writer application architecture, stored functions can obscure application behavior. Database-owned invariants and expression indexes may still require approved stored functions.

Fix

Prefer declarative constraints or explicit transactional application behavior where equivalent. Preserve transaction atomicity and database-enforced integrity; use an exact SARJ120 suppression for an approved database-owned invariant or compatibility exception.

Examples

Before — flagged An executable anonymous block still creates a stored function
migrations/001_function.sql
DO $outer$ BEGIN CREATE FUNCTION app.f() RETURNS integer LANGUAGE sql AS $inner$SELECT 1$inner$; END $outer$;
After — preferred Function DDL stored as scalar data does not execute
migrations/001_function.sql
SELECT
$outer$CREATE FUNCTION app.f() RETURNS integer LANGUAGE sql AS $inner$SELECT 1$inner$;$outer$;
Before — flagged Procedural database fault fixture
supabase/migrations/001.sql
CREATE FUNCTION fail_counter () RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN RAISE EXCEPTION 'failure'; END $$;
After — preferred Declarative constraint in a disposable test database
supabase/migrations/001.sql
ALTER TABLE batch
ADD CONSTRAINT fail_counter CHECK (FALSE) NOT VALID;