"Supabase updated_at Not Updating? Fix with Triggers"

"Fix supabase updated_at not updating: BEFORE UPDATE triggers, moddatetime, handle_new_user signup triggers, pg_net HTTP notifications. Copy-paste SQL."

You added an updated_at column to your table, set a default of now() , and shipped it. Weeks later you notice every row still shows its creation time — supabase updated_at not updating is one of the most common Postgres gotchas, and the fix is a database trigger: a small function Postgres runs automatically before every UPDATE. In this guide you'll fix updated_at with a BEFORE UPDATE trigger, learn the zero-code moddatetime alternative, build the classic handle_new_user signup trigger, understand BEFORE vs AFTER, and send HTTP requests from triggers with pg_net . All SQL is copy-paste ready for the Supabase SQL editor. Last updated: October 3, 2026 What you'll learn Why updated_at with default now() never updates (and the trigger fix) BEFORE vs AFTER triggers — which one, when The moddatetime() zero-code alternative The handle_new_user trigger: creating a profile on signup Sending HTTP requests from triggers with pg_net Debugging triggers that don't fire Why "supabase updated_at not updating" Happens A column default only fires on INSERT. When you UPDATE a row, Postgres leaves every other column untouched — including updated_at . Nothing is broken; the database is doing exactly what you asked. What you actually want is: *before every UPDATE, set NEW.updated_at = now() *. That's a trigger — a function bound to a table event. -- 1. The trigger function: runs for each updated row create or replace function public.handle_updated_at() returns trigger language plpgsql as $ begin -- NEW is the row about to be written; modify it before it lands. new.updated_at = now(); return new; end; $; -- 2. Bind it to the table: BEFORE UPDATE, FOR EACH ROW create trigger set_updated_at before update on public.posts for each row execute function…

Explore