Triggers Basics
9 examples to get you started with PostgreSQL triggers - 6 basic and 3 intermediate.
Search across all documentation pages
9 examples to get you started with PostgreSQL triggers - 6 basic and 3 intermediate.
Table with INSERT/UPDATE you can modify in dev.
# Local dev with Docker (PostgreSQL 18)
docker run -d --name pg18 -e POSTGRES_PASSWORD=dev -p 5432:5432 postgres:18
psql postgres://postgres:dev@localhost:5432/postgresRuns per inserted row.
CREATE OR REPLACE FUNCTION app.log_insert() RETURNS trigger
LANGUAGE plpgsql AS $$
BEGIN
RAISE NOTICE 'inserted %', NEW.id;
RETURN NEW;
END;
$$;
CREATE TRIGGER tr_log_insert AFTER INSERT ON app.accounts
FOR EACH ROW EXECUTE FUNCTION app.log_insert();Can modify NEW before write.
CREATE OR REPLACE FUNCTION app.touch_updated() RETURNS trigger
LANGUAGE plpgsql AS $$
BEGIN
NEW.updated_at := now();
RETURN NEW;
END;
$$;Fires once per SQL statement.
CREATE TRIGGER tr_stmt AFTER UPDATE ON app.accounts
FOR EACH STATEMENT EXECUTE FUNCTION app.log_insert();Remove when logic moves to app.
DROP TRIGGER IF EXISTS tr_log_insert ON app.accounts;BEFORE vs AFTER choice.
-- BEFORE: validate/modify NEW
-- AFTER: audit/side effects referencing final rowConditional trigger fire.
CREATE TRIGGER tr_status AFTER UPDATE OF status ON app.orders
FOR EACH ROW WHEN (OLD.status IS DISTINCT FROM NEW.status)
EXECUTE FUNCTION app.log_insert();Alphabetical name order by default.
CREATE TRIGGER a_first BEFORE INSERT ON app.accounts FOR EACH ROW EXECUTE FUNCTION app.touch_updated();
CREATE TRIGGER b_second BEFORE INSERT ON app.accounts FOR EACH ROW EXECUTE FUNCTION app.log_insert();Deferred constraint checking.
-- CONSTRAINT TRIGGER ... DEFERRABLE INITIALLY DEFERREDSession_replication_role or ALTER TABLE DISABLE.
ALTER TABLE app.accounts DISABLE TRIGGER tr_log_insert;
-- bulk load
ALTER TABLE app.accounts ENABLE TRIGGER tr_log_insert;Stack versions: This page was written for PostgreSQL 18.4 (stable 18, maintenance 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, and PostGIS 3.5+.
Reviewed by Chris St. John·Last updated Jul 16, 2026