# What is a background job?

Source: https://www.plutonapps.com/resources/what-is-a-background-job

Published 2026-09-30, updated 2026-10-24, sources checked 2026-10-24. By Irfan Habib (https://www.plutonapps.com/authors/irfan-habib).

**Background job:** A background job is a piece of work an application does outside the request a user is waiting on, such as sending an email, resizing an upload or syncing with another service. Jobs wait on a queue for separate workers, which can retry a failure unseen.

Also known as: Async task.

Everything slow, risky or scheduled belongs here: out of the user's way, and able to try again.

## Why do slow tasks belong in a background job, not the request?

Because the user should not wait for work that does not need them, and a request that times out halfway leaves nobody knowing what finished. Microsoft's guide gives the test: a task suits a background job when it can run without user interaction and the screen does not have to wait for it.

Prototypes tend to do everything inside the request: click send, and the page waits while the app emails 2,000 subscribers. It works with five. A background job turns that into a recorded unit of work. The request only has to put the job on the queue; a worker does the job, marks it done, and retries it if it fails.

## What starts a background job?

Either an event or a clock. Microsoft's guide splits triggers into event-driven ones, where a user action or workflow step puts a message on a queue, and schedule-driven ones, where a timer runs the task on a recurring schedule or once at a set time.

| Trigger | Typical jobs |
| --- | --- |
| Event-driven | Sending email, processing uploaded images, calling other services, setting up new users |
| Schedule-driven | Nightly batch updates, daily reports, data retention clean-up, consistency checks |

## What makes a background job reliable?

Assuming it will run more than once. Microsoft's guide says queues deliver messages at least once, schedulers can overlap, and restarts can replay half-finished work, so every job must be [idempotent](https://www.plutonapps.com/resources/what-is-idempotency): the same input gives the same outcome however many times it runs.

- Poison messages: a message that fails every time can block the queue, so detect it and move it aside to a dead-letter queue instead of retrying forever.
- Transient or permanent: retry a timeout, but send a malformed payload straight to the dead-letter queue.
- Track completion, not only starts: a job that hangs silently looks like one that is running.
- Alert on missed schedules, because a scheduled job that never fired raises no error.
- Measure queue wait time: a job that takes 2 seconds but waits 30 minutes is a 30-minute delay.

## How do you run background jobs in a Supabase app?

Supabase Queues is a durable message queue built into Postgres on the pgmq extension. Its documentation says messages are guaranteed to be delivered, each one exactly once to a consumer within a visibility window you set, and can be archived for auditing.

Access is controlled with API permissions and row-level security. Email sends are the usual first job to move there: see our guide to [sending email from Lovable with Resend](https://www.plutonapps.com/resources/lovable-resend-email).

## How do Inkwave and Ripply run background jobs in production?

Both run slow work outside the request, in a form that survives retries and stays visible. Inkwave sends newsletters as a durable workflow that resumes where it stopped, and Ripply shows its job and webhook backlogs to the people running the platform. The details are below.

> **What we see in practice** [Inkwave](https://www.plutonapps.com/work/inkwave) sends each newsletter as a durable workflow, in batches of 100 recipients, and records every batch as done exactly once, so a retry picks up where it stopped and never re-sends. [Ripply's](https://www.plutonapps.com/work/ripply) operator console shows its job and webhook backlogs alongside incidents, so a stuck queue is visible to the people running the platform.

If your app still sends in the request and times out, our [vibe coding rescue](https://www.plutonapps.com/services/vibe-coding-rescue) moves that work behind a queue.

## Frequently asked questions

### What is the difference between a background job and a cron job?

A cron job runs on a schedule, such as every night at 2am. A background job can also run when something asks for it, such as a user placing an order. Microsoft's guide calls these schedule-driven and event-driven triggers. Many apps use both, often through the same queue and workers.

### Why do background jobs need to be idempotent?

Because they will sometimes run twice. Microsoft's guide notes that queues deliver messages at least once, that a job can fail after doing its work but before deleting its message, and that restarts replay unfinished work. If running a job twice sends two emails, users will eventually get two.

### What is a poison message?

A queued message that makes the job fail every time it is processed, often because its data is malformed. Retried forever, it can block the queue and eventually the application. Microsoft's guide recommends detecting such messages and moving them to a dead-letter queue, where someone can inspect and resubmit them.

### Does Supabase have a job queue?

Yes. Supabase Queues is a Postgres-native durable message queue built on the pgmq extension. Its documentation says messages are guaranteed to be delivered, each one exactly once to a consumer within a configurable visibility window, and that consumer access can be controlled with API permissions and row-level security.

## Read next

- [The Inkwave case study: newsletters sent in durable batches of 100](https://www.plutonapps.com/work/inkwave)
- [The Bell case study: a ledger that sends each email exactly once](https://www.plutonapps.com/work/bell)

## Sources

- [Microsoft Azure Architecture Center: Best practices for background jobs](https://learn.microsoft.com/en-us/azure/architecture/best-practices/background-jobs)
- [Supabase documentation: Supabase Queues](https://supabase.com/docs/guides/queues)
