Running background jobs directly in Postgres is surprisingly effective for many workloads. pg_cron schedules SQL at the database level, and pg_net can call HTTP endpoints from inside Postgres. Together they let you automate tasks without a separate worker.
Install the extensions
CREATE EXTENSION IF NOT EXISTS pg_cron;
CREATE EXTENSION IF NOT EXISTS pg_net;
Make sure pg_cron is configured with the right database in postgresql.conf.
Example: nightly cleanup
SELECT cron.schedule(
'nightly_cleanup',
'0 2 * * *',
$$DELETE FROM audit_logs WHERE created_at < now() - interval '90 days'$$
);
Example: ping a webhook
SELECT net.http_post(
url := 'https://example.com/webhooks/daily-rollup',
headers := '{"Authorization": "Bearer token"}'::jsonb,
body := '{"source":"pg_cron"}'::jsonb
);
Observability tips
- Store
cron.job_run_detailsin a dashboard table. - Add a short retention policy for old runs.
- Emit alerts for consecutive failures.
When to use this pattern
If your task is data-local and short-lived, pg_cron is a clean fit. For long-running or CPU-heavy jobs, keep a separate worker process.
About the author
Samuel Owhondah is a software engineer with a background in Electrical and Electronics Engineering and a Master's degree in Computing (Software Engineering). He specializes in building scalable, user-focused web applications using React, Next.js, TypeScript, and Python-based backends.