Tinyjobs brings zero-dependency background tasks to Python on SQLite
A new library enables background jobs and cron scheduling for Python apps using only SQLite, with no external dependencies required.
GitHub user Piergiuseppe has released tinyjobs, a lightweight library for managing background jobs and cron schedules in Python applications. Published on October 27, 2026, the project allows developers to run asynchronous and synchronous tasks using SQLite as the sole backend, eliminating the need for complex message brokers like Redis or RabbitMQ for small to mid-sized deployments.
What happened
The release introduces a zero-dependency approach to job scheduling, targeting developers who want to avoid the operational overhead of maintaining separate infrastructure for task queues. Tinyjobs supports both FastAPI and Django frameworks, integrating directly into their lifecycles. For FastAPI, it uses the lifespan context manager to start a worker within the server process, ensuring that in-flight jobs complete gracefully during shutdown. In Django, it acts as a backend for the standard django.tasks API introduced in Django 6, allowing tasks to remain plain Python code while leveraging tinyjobs for execution.
The library handles common requirements such as retries with exponential backoff, cron scheduling with timezone support, and job deduplication. It operates on an at-least-once delivery model, meaning tasks may execute more than once if a worker crashes after processing but before recording the result. To mitigate this, developers are advised to write idempotent tasks. The system uses lease-based locking to ensure that if a worker dies, its assigned jobs become available to other workers after a timeout period.
Key details
- Zero dependencies: Runs entirely on SQLite by default, requiring no external services for small setups.
- Framework integration: Native support for FastAPI via lifespan hooks and Django via the
django.tasksbackend. - Concurrency model: Supports both
async deftasks running on the event loop anddeftasks executed in a thread pool. - Redis option: An optional Redis backend is available for multi-machine deployments, using Lua scripts for atomic operations.
- Testing utilities: Includes a memory-based backend and a frozen clock for deterministic testing of delayed jobs and retries.
- Observability: Provides built-in commands for checking queue stats and health, including detection of overdue cron jobs.
Background
Background job systems allow applications to offload time-consuming tasks, such as sending emails or generating reports, from the main request-response cycle. Traditionally, this requires a message broker like Redis, RabbitMQ, or PostgreSQL, which adds complexity to deployment and monitoring. SQLite is often dismissed for concurrent write scenarios, but tinyjobs leverages specific SQL features like RETURNING and immediate transactions to safely manage job claims across multiple worker processes. This approach simplifies the stack for applications that do not yet require the scale of distributed systems.
Why it matters
For teams running self-hosted software, reducing infrastructure complexity is a significant advantage. Maintaining a Redis instance or a RabbitMQ cluster requires dedicated resources, monitoring, and backup strategies. By using SQLite, tinyjobs allows small and mid-sized companies to keep their entire application stack within a single database file. This reduces the attack surface and simplifies backups, as the job queue is included in standard database dumps. It also lowers the barrier to entry for adding background processing to existing projects without refactoring the entire architecture.
However, this simplicity comes with trade-offs. SQLite does not support true parallel writes across different machines, so the default backend is limited to a single server. While the Redis backend addresses this, it reintroduces the dependency the library aims to avoid. Additionally, the at-least-once delivery model requires careful task design to prevent duplicate side effects, such as charging a customer twice. Teams must weigh the operational ease against these technical constraints when choosing a job scheduler.
What you can do
- Evaluate your scale: If your application runs on a single server or a small cluster, test tinyjobs with SQLite to see if it meets your throughput needs.
- Check idempotency: Review existing background tasks to ensure they can be safely retried without causing data corruption or duplicate actions.
- Test shutdown behavior: Use the provided lifespan hooks in FastAPI or Django to verify that jobs complete or requeue correctly during deployment restarts.
- Monitor leases: Configure appropriate lease timeouts based on your longest-running tasks to prevent premature re-execution if a worker hangs.
- Consider Redis for growth: Plan for a migration path to the Redis backend if you anticipate scaling beyond a single machine, ensuring your tasks are compatible with network latency.
- Use built-in checks: Implement regular health checks using
tinyjobs checkto detect stalled workers or missed cron schedules early.



