diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
index e40c690b7e931..a053d8a96a2cc 100644
--- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
+++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
@@ -1045,6 +1045,10 @@ export const database: NavMenuConstant = {
name: 'Managing connections',
url: '/guides/database/connection-management' as `/${string}`,
},
+ {
+ name: 'Managing event triggers',
+ url: '/guides/database/postgres/event-triggers' as `/${string}`,
+ },
],
},
{
diff --git a/apps/docs/content/guides/database/postgres/event-triggers.mdx b/apps/docs/content/guides/database/postgres/event-triggers.mdx
new file mode 100644
index 0000000000000..0254f74757eba
--- /dev/null
+++ b/apps/docs/content/guides/database/postgres/event-triggers.mdx
@@ -0,0 +1,135 @@
+---
+id: 'postgres-event-triggers'
+title: 'Event Triggers'
+description: 'Automatically execute SQL on database events.'
+subtitle: 'Automatically execute SQL on database events.'
+---
+
+In Postgres, an [event trigger](https://www.postgresql.org/docs/current/event-triggers.html) is similar to a [trigger](/docs/guides/database/postgres/triggers), except that it is triggered by database level events (and is usually reserved for [superusers](/docs/guides/database/postgres/roles-superuser))
+
+With our `Supautils` extension (installed automatically for all Supabase projects), the `postgres` user has the ability to create and manage event triggers.
+
+Some use cases for event triggers are:
+
+- Capturing Data Definition Language (DDL) changes - these are changes to your database schema (though the [pgAudit](/docs/guides/database/extensions/pgaudit) extension provides a more complete solution)
+- Enforcing/monitoring/preventing actions - such as preventing tables from being dropped in Production or enforcing RLS on all new tables
+
+The guide covers two example event triggers:
+
+1. Preventing accidental dropping of a table
+2. Automatically enabling Row Level Security on new tables in the `public` schema
+
+## Creating an event trigger
+
+Only the `postgres` user can create event triggers, so make sure you are authenticated as them. As with triggers, event triggers consist of 2 parts
+
+1. A [Function](/docs/guides/database/functions) which will be executed when the triggering event occurs
+2. The actual Event Trigger object, with parameters around when the trigger should be run
+
+### Example trigger function - prevent dropping tables
+
+This example protects any table from being dropped. You can override it by temporarily disabling the event trigger: `ALTER EVENT TRIGGER dont_drop_trigger DISABLE;`
+
+```sql
+-- Function
+CREATE OR REPLACE FUNCTION dont_drop_function()
+ RETURNS event_trigger LANGUAGE plpgsql AS $$
+DECLARE
+ obj record;
+ tbl_name text;
+BEGIN
+ FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects()
+ LOOP
+ IF obj.object_type = 'table' THEN
+ RAISE EXCEPTION 'ERROR: All tables in this schema are protected and cannot be dropped';
+ END IF;
+ END LOOP;
+END;
+$$;
+
+-- Event trigger
+CREATE EVENT TRIGGER dont_drop_trigger
+ON sql_drop
+EXECUTE FUNCTION dont_drop_function();
+```
+
+### Example trigger function - auto enable Row Level Security
+
+```sql
+CREATE OR REPLACE FUNCTION rls_auto_enable()
+RETURNS EVENT_TRIGGER
+LANGUAGE plpgsql
+SECURITY DEFINER
+SET search_path = pg_catalog
+AS $$
+DECLARE
+ cmd record;
+BEGIN
+ FOR cmd IN
+ SELECT *
+ FROM pg_event_trigger_ddl_commands()
+ WHERE command_tag IN ('CREATE TABLE', 'CREATE TABLE AS', 'SELECT INTO')
+ AND object_type IN ('table','partitioned table')
+ LOOP
+ IF cmd.schema_name IS NOT NULL AND cmd.schema_name IN ('public') AND cmd.schema_name NOT IN ('pg_catalog','information_schema') AND cmd.schema_name NOT LIKE 'pg_toast%' AND cmd.schema_name NOT LIKE 'pg_temp%' THEN
+ BEGIN
+ EXECUTE format('alter table if exists %s enable row level security', cmd.object_identity);
+ RAISE LOG 'rls_auto_enable: enabled RLS on %', cmd.object_identity;
+ EXCEPTION
+ WHEN OTHERS THEN
+ RAISE LOG 'rls_auto_enable: failed to enable RLS on %', cmd.object_identity;
+ END;
+ ELSE
+ RAISE LOG 'rls_auto_enable: skip % (either system schema or not in enforced list: %.)', cmd.object_identity, cmd.schema_name;
+ END IF;
+ END LOOP;
+END;
+$$;
+
+DROP EVENT TRIGGER IF EXISTS ensure_rls;
+CREATE EVENT TRIGGER ensure_rls
+ON ddl_command_end
+WHEN TAG IN ('CREATE TABLE', 'CREATE TABLE AS', 'SELECT INTO')
+EXECUTE FUNCTION rls_auto_enable();
+```
+
+### Event trigger Functions and firing events
+
+Event triggers can be triggered on:
+
+- `ddl_command_start` - occurs just before a DDL command for almost all objects within a schema
+- `ddl_command_end` - occurs just after a DDL command for almost all objects within a schema
+- `sql_drop` - occurs just before `ddl_command_end` for any DDL commands that `DROP` a database object (note that altering a table can cause it to be dropped)
+- `table_rewrite` - occurs just before a table is rewritten using the `ALTER TABLE` command
+
+