Event triggers fire a user-defined function in response to database-wide events such as DDL commands, enabling global auditing, security, and automation.
Event triggers execute a stored function when high-level events—CREATE, ALTER, DROP, TRUNCATE, or a SQL session start—occur. Unlike table triggers, they watch the entire database, letting you audit DDL, block risky changes, or rebuild metadata automatically.
Use event triggers to log schema changes, enforce naming conventions, refresh materialized views after bulk loads, or prevent table drops in production. Because they run for every matching command, reserve them for tasks that truly need database-wide scope.
Write a SECURITY DEFINER function in PL/pgSQL, then bind it with CREATE EVENT TRIGGER
. Choose the event (ddl_command_start
, ddl_command_end
, sql_drop
, etc.) and optional filter tags such as ALTER TABLE
.
The snippet below records every table change in an audit_ddl
table. In an ecommerce app, this helps track accidental changes to Orders
or Products
.
CREATE TABLE audit_ddl(log_id serial PRIMARY KEY,
event text,
command text,
executed_at timestamptz DEFAULT now());
CREATE OR REPLACE FUNCTION log_ddl() RETURNS event_trigger
LANGUAGE plpgsql AS $$
BEGIN
INSERT INTO audit_ddl(event, command)
SELECT tg_tag, current_query();
END;$$;
CREATE EVENT TRIGGER trg_audit_ddl
ON ddl_command_end
EXECUTE FUNCTION log_ddl();
Query pg_event_trigger
or run \dE+
in psql to see trigger names, events, and enabled status.
Disable a trigger with ALTER EVENT TRIGGER trg_name DISABLE;
, enable it again with ENABLE;
, or remove it entirely using DROP EVENT TRIGGER trg_name;
.
Keep trigger functions lightweight—off-load heavy work to background jobs. Always wrap data-modifying statements in EXCEPTION
blocks to avoid cascading failures. Version-control the trigger code with the rest of your schema.
Recursive effects: An event trigger that issues DDL can fire itself repeatedly. Use SET LOCAL session_replication_role = replica
or check tg_tag
to short-circuit recursion.
Over-filtering: Forgetting WHEN TAG IN ('ALTER TABLE')
means the trigger fires on every DDL, hurting performance. Specify only the tags you need.
No. Event triggers watch database-level events like DDL, not row-level changes. Use table triggers for data-change events.
Yes. If the trigger raises an error, the entire DDL command rolls back, ensuring atomicity.
Use WHEN TAG IN ('ALTER TABLE','DROP TABLE')
. The trigger fires only for the listed command tags.