What it is
A scheduling submodule that lets a SpacetimeDB application run recurring tasks on either a calendar-based schedule or a fixed time interval. It lives inside the server-side module, storing all schedule state directly in the database so schedules can be inspected, changed, or cancelled at runtime without redeploying.
Where it fits
- Periodic cleanup: An app that needs to purge stale sessions, expired tokens, or old log rows on a nightly or hourly basis.
- Scheduled reports: A multi-tenant SaaS product that generates per-workspace summaries every weekday morning in the workspace's local time zone.
- Polling external services: A module that needs to sync data from a third-party API on a fixed cadence, using a stable invocation identifier for safe retries.
- Parameterized background jobs: A workflow system where each tenant or resource needs its own scheduled job with different arguments, such as archiving a specific workspace after a configurable retention period.
- Resilient recurring work: Any situation where a missed or crashed job must be detected and recovered automatically rather than silently dropped.
How it works
Each job is declared as a named slot that the module registers at startup. A job can carry typed arguments stored alongside its schedule, so the handler always receives the exact payload that was set when the job was last configured. Schedules live in ordinary database tables, which means the application can create, replace, or remove them inside any reducer with the same transactional guarantees as any other database write.
When a calendar job fires, the next occurrence is calculated and committed before the handler runs, so a crash mid-execution does not permanently lose the schedule. If something goes wrong during a run, a recovery step records the failure and restores the trigger in a separate transaction. A background sweep can be configured to periodically scan for jobs that somehow lost their trigger, catching edge cases that the per-operation repair might miss. Fixed-interval jobs use the database's native scheduling mechanism and are inherently self-sustaining.
Clients can subscribe to a public view of job status, including whether a job is enabled, when it is next expected to run, and how many consecutive failures it has recorded. A job can be configured to disable itself automatically after a threshold of consecutive failures, preventing a broken handler from retrying indefinitely. Run history is kept up to a configurable cap per job, giving operators a lightweight audit trail without unbounded table growth.

