Supabase cron jobs.
pg_cron handles scheduled SQL. When the job needs to call an API, retry on failure, or run a model, here is what to do instead.
What pg_cron handles for Supabase cron jobs.
pg_cron runs SQL on a cron schedule inside your database: cleanups, aggregations, function calls. Supabase Cron, the module built on it, also schedules HTTP requests to any webhook and Supabase Edge Functions. Two things to know before you build on it: schedules are UTC with no conversion UI (9 AM Eastern is 2 PM UTC), and HTTP and Edge Function calls go through pg_net, which fires the request and does not retry it. Supabase Queues, built on pgmq, can hold work in Postgres until a consumer processes it. For scheduled SQL, pg_cron works. When one job needs a query, a model call, an email, and a retry for each step, the logic needs a place to run outside the database.
-- Schedule a daily cleanup at 3am UTC (not your local time) SELECT cron.schedule( 'daily-cleanup', '0 3 * * *', $$DELETE FROM logs WHERE created_at < now() - interval '30 days'$$ ); -- Check what ran SELECT * FROM cron.job_run_details ORDER BY start_time DESC LIMIT 10;
qbash Tasks.
A Task is an AI automation written in Python, hosted on a managed runtime. A developer writes the script; anyone runs it from a form. Integrations, model calls, version control, and logging are built in.
Model and provider agnostic.
Anthropic
OpenAI
Gemini
xAI
OpenRouterAmazon
PerplexityMoonshotAI
MetaQwen
Writing the job as a Python script.
When a scheduled job needs to query your database, call a third-party API, send an email, and update a record, that is a script, not a SQL statement. A qbash Task is a Python script that runs on a managed runtime. It connects to your Supabase database directly and calls integrations in code. You set the schedule in your timezone, not UTC. If a run fails partway through, the next attempt picks up from the last checkpoint instead of reprocessing work that already finished. Your data stays on Supabase. The script runs against it on a schedule.
users = qbash.integrations.supabase.execute_sql( query="SELECT * FROM users " "WHERE trial_ends_at < now() AND reminded = false" )["rows"] for user in users: email = qbash.ai.run_prompt( slug="trial-ending-email", variables={"name": user["name"], "plan": user["plan"]}, ) qbash.integrations.outlook.send_message( to_recipients=user["email"], subject="Your trial is ending", body=email["body"], ) qbash.integrations.postgres.execute_query( query="UPDATE users SET reminded = true WHERE id = $1", query_params=[user["id"]], )
Retry, database access, and delivery.
When a job reaches past the database, it needs to handle partial failures, query data from multiple sources, and deliver results where the team works.
Checkpoints and retry
qbash.parallel processes a list of items and records each one as it finishes. If the run fails at item 40 of 200, the retry starts at item 41. In a pg_cron job, there is no concept of partial progress. A failure means the next scheduled run starts the entire job from the beginning, and any side effects from the first attempt (emails sent, records updated) have already happened.
result = qbash.parallel( send_reminder, users, concurrency=5, max_per_minute=60, checkpoint="trial-reminders", retry=3, )
Direct database access
Two ways to reach your data. The Supabase integration calls the Management API for storage buckets, migrations, and admin operations. The Postgres integration connects directly to the underlying database for parameterized queries and transactions. Credentials are stored on the server and never appear in your script or logs.
# Supabase Management API rows = qbash.integrations.supabase.execute_sql( query="SELECT * FROM orders WHERE status = 'pending'" )["rows"] # Or connect directly to the underlying Postgres rows = qbash.integrations.postgres.execute_query( query="SELECT * FROM orders WHERE status = $1", query_params=["pending"], )["result"]
Delivery in one line
From pg_cron, posting to Slack or writing to a CRM is an HTTP request through pg_net, with the payload built in SQL and no retry if the call fails. In a Task, each of those is a function call in the script, called the same way you would call any other Python function.
qbash.integrations.slack.create_message( channel="#ops", text=f"Reminded {len(users)} users about expiring trials", ) qbash.integrations.outlook.send_message( to_recipients="team@example.com", subject="Weekly trial report", body=report["summary"], )
Questions
Does this replace Supabase?
No. Your database stays on Supabase. qbash runs the scheduled job and talks to your database as a data source. pg_cron is still the right tool for scheduled SQL that does not need retries or external calls.
How do I handle RLS with pg_cron?
Plain SQL jobs usually are not affected, because pg_cron runs them as the postgres role, which owns your tables by default. RLS comes into play when the job calls an Edge Function or the REST API over HTTP. Send the service role key in the request, or the call runs as the anon role and policies that check auth.uid() filter it out. In qbash, the database call is server-side and does not run inside a Postgres session, so RLS policies that check auth.uid() do not apply.
Can I still use pg_cron for simple jobs?
Yes. pg_cron is the right tool for scheduled SQL: cleanups, aggregations, partition maintenance. Move the job to a Task when it needs retries, external API calls, model calls, or runs longer than a database transaction should.
What about Edge Functions on a schedule?
Edge Functions work for short, stateless HTTP handlers. pg_net invocation from pg_cron is fire-and-forget with no retry on failure. A Task handles longer, stateful work with checkpoint-resumable retries and logging.
How does timezone handling work in qbash?
The cron schedule uses the timezone you set in the task settings. pg_cron uses UTC with no conversion UI, which is the source of most scheduling confusion in the Supabase community.
Competitor details reviewed . Vendors change plans and features without notice, so check theirs before deciding.
Related
Ship your first task.
Write a script against your Supabase database, set a cron schedule, and the platform handles retries, logging, and deployment.