Start Here
Some scheduled jobs are just database work with a clock.
Refresh a rollup. Delete expired rows. Queue reminders. Recompute a summary table. If the job mostly runs SQL, a separate scheduler may be extra machinery.
pg_cron lets Postgres run scheduled SQL.
What To Build First
Install the extension and schedule one clear job.
create extension if not exists pg_cron;
select cron.schedule(
'nightly-rollup',
'0 2 * * *',
$$call refresh_account_rollups()$$
);
Use names you can read. A job called nightly-rollup is easier to debug than a random identifier.
You can inspect scheduled jobs from SQL:
select jobid, schedule, command, active
from cron.job;
Good First Uses
- Cleanup tasks.
- Rollups and summary refreshes.
- Database maintenance jobs.
- Moving due rows into a queue.
- Small recurring tasks that already live near Postgres.
This is a good fit when the job is database-local.
The Part People Skip
Write job results somewhere.
If a scheduled job matters, you should be able to answer three questions quickly:
- Did it run?
- Did it fail?
- How many rows did it touch?
Do not rely only on logs. Add a small job audit table if the result matters to the product.
What This Does Not Replace
pg_cron is not a workflow engine.
It does not give you a product UI for approvals, dependency graphs, long-running external work, or rich pause/resume controls. It schedules SQL.
That is exactly why it is useful for the right jobs.
Move To A Scheduler Or Workflow Tool When
- Jobs call many external services.
- Jobs need approvals, dependencies, or manual controls.
- Non-database teams need to own schedules.
- The job history is a product or operations requirement.
- Failures need richer retry and alerting behavior than SQL gives you.
Until then, keep database-local recurring work close to the database.