Scheduling on Supabase, inside the database and outside it
Supabase Cron is pg_cron running inside your database, which makes it excellent for SQL and awkward for everything else. Here is where the line falls.
What Supabase gives you
Supabase Cron. A Postgres module built on pg_cron. Jobs are rows in your database and can run SQL directly, call a database function, or make an HTTP request to an Edge Function.
- Granularity
- Every second to once a year
- Runs where
- Inside your Postgres instance
- Recommended concurrency
- No more than 8 jobs at once
- Recommended job length
- Under 10 minutes
- Free plan projects
- Paused after about a week of inactivity
Checked against Supabase docs on 18 August 2026. These change — if a deploy disagrees with this page, believe the deploy and tell us.
When this is the right answer
Most people reading this should keep what they have. It is worth being specific about when:
- The job is SQL — a nightly aggregate, a cleanup, a refresh of a materialized view. Running that next to the data with no network hop is the right design and nothing external will beat it.
- You are on a paid plan and the work is small and database-shaped.
Where it runs out
A paused free project runs nothing
Supabase pauses free projects after roughly a week without sufficient activity. A scheduler that stops when the thing it lives inside goes to sleep is a scheduler you have to think about.
Your scheduler competes with your database
pg_cron jobs consume the same connections and CPU as your application queries. The guidance to keep jobs under ten minutes and under eight concurrent is not arbitrary — it is the cost of living in the database.
Observability is a table you have to query
Run history lives in cron.job_run_details. There is no alert when a job stops firing; you find out by going and looking, which is the one thing nobody does on a schedule.
Calling anything outside Postgres is indirect
HTTP from pg_cron goes through pg_net, so an ordinary "call this API every ten minutes" becomes a database extension concern with retries and error handling to match.
Scheduling it from outside
The useful split: keep SQL work in pg_cron, and move anything that reaches the network out to an HTTP scheduler. If the job is a call to an Edge Function, calling it directly removes a layer.
An Edge Function is just a URL
POST https://<project-ref>.supabase.co/functions/v1/your-function
Authorization: Bearer <service-role-key>Store that key as a secret header on the job — it is encrypted at rest and never returned by the API. You then get retries, a record of every run and an alert when one fails, none of which pg_cron gives you.
What getNodi adds
getNodi calls a URL on a schedule and tells you what happened. Any schedule down to your plan’s floor, in your timezone rather than UTC, with retries, a record of every run — status, latency, response — and an alert the first time one fails. Credentials are encrypted at rest and requests can be HMAC-signed so your endpoint can verify they came from us.
The free plan runs 3 jobs hourly and needs no card, which is enough to find out whether this works for you. What it will not do is run a container, hold a connection open for an hour, or execute your code — it makes HTTP requests, and everything above is a way of making that enough.