pg_cron is a Postgres extension that lets you schedule SQL jobs inside your database. No external scheduler. No Lambda functions. No cron servers. Just SQL on a timer.
I have 38 pg_cron jobs running across my Supabase project right now. They handle everything from publishing articles to scraping county records to refreshing lead scores. Here is how I set it up and why it matters.
What pg_cron Actually Does
You write a SQL statement. You give it a cron expression. Postgres runs it on schedule. That is it.
SELECT cron.schedule(
'publish-content-daily',
'0 9 * * *',
$$SELECT net.http_post(
url := 'https://yourproject.supabase.co/functions/v1/publish-build-content',
headers := '{"Content-Type": "application/json"}'::jsonb,
body := '{"platform": "devto", "limit": 3}'::jsonb
);$$
);
That job fires every day at 9 AM and publishes 3 articles from my content queue. No server. No GitHub Action. No third party.
My 38 Jobs
Here is the breakdown by category:
Content Pipeline (4 jobs) — Auto-draft articles from build logs, publish to dev.to, refresh content calendar, clean up failed drafts.
Lead Pipeline (14 jobs) — Scrape 14 Texas counties nightly for foreclosures, delinquent taxes, code violations, and 311 complaints. Each county gets its own job so failures are isolated.
Lead Scoring (3 jobs) — Recalculate scores daily, flag hot leads, archive stale ones older than 90 days.
Communication (5 jobs) — Send follow-up sequences, check voicemail transcriptions, rotate DID assignments, refresh VAPI agent configs.
Maintenance (12 jobs) — Vacuum tables, refresh materialized views, rotate logs, check API key expiry, monitor edge function error rates.
Why This Beats External Schedulers
- Zero cold starts — The job runs inside Postgres. No Lambda spin-up. No container boot.
- Transactional — Your scheduled job can read and write the same database in one transaction. Try doing that with a Zapier webhook.
- Free — pg_cron is included in every Supabase plan. No per-execution billing.
-
Observable — Query
cron.job_run_detailsto see every execution, runtime, and error.
The Gotcha
pg_cron runs in UTC. If you are in Central Time like me, 9 AM CT is 0 14 * * * in cron syntax. Get this wrong and your jobs fire at 3 AM. Ask me how I know.
Bottom Line
If you are on Supabase and you are not using pg_cron, you are leaving automation on the table. It is the closest thing to a free operations team I have found.
Top comments (0)