Queues
A Queue is an asynchronous work transport and execution system.
Use queues when work needs to run outside the request path, use workers, retry, delay, timeout, or move across process boundaries.
When To Use Queues
| Question | Guidance |
|---|---|
| Use this when | Work should run outside the request path or be processed by workers. |
| Avoid this when | The result must be available before returning the current response. |
| Start with | sync or workerpool for one-process local development. |
| Upgrade to | SQLite, Redis, SQL, NATS, SQS, RabbitMQ, or another shared backend when API and workers split or work needs durable state. |
Generated Package
Generated queue code lives in:
internal/queuesThe generated package builds the default queue from QUEUE_* variables and optional named queues from QUEUE_<NAME>_* variables.
Configure a named queue with:
forj make:queue reports --workers 2This updates the queue section in .env:
QUEUE_REPORTS_NAME=reports
QUEUE_REPORTS_WORKERS=2Run forj make:queue without arguments in an interactive terminal to use the resource wizard. Use --name only when the backend queue name should differ from the App-facing queue name:
forj make:queue reports --workers 2 --name production-report-jobsAccessors
Generated Apps expose queues through default and named accessors:
queue := app.Queue()
critical := app.Queues().Critical()Named accessors are generated invariants. If a named accessor is missing or misaligned with runtime environment, the App should fail fast.
Use named queues when the App has distinct classes of work. For example, emails, reports, and critical can each have their own generated accessor, backend configuration, worker count, metrics labels, and operational process.
One generated queue resource represents one queue. The resource name is the app-facing queue name, and by default it is also the backend queue name. Use QUEUE_<NAME>_NAME only when the backend queue name must differ.
Driver Configuration
Compile-time support:
QUEUE_SUPPORTED_DRIVERS=workerpool,redisRuntime selection:
QUEUE_DRIVER=workerpool
QUEUE_CRITICAL_DRIVER=redis
QUEUE_NAME=default
QUEUE_WORKERS=30
QUEUE_SHUTDOWN_TIMEOUT=10sUse sync or workerpool locally. Use durable or broker-backed drivers when production work needs shared state, retries, and independent workers.
Named queues inherit the root queue driver unless they override it:
QUEUE_DRIVER=redis
QUEUE_EMAILS_WORKERS=6
QUEUE_REPORTS_WORKERS=2In this example, both named queues use Redis. emails gets more worker capacity than reports, so it is prioritized by runtime allocation rather than by leaking backend-specific weighting into the main App model.
Use about to verify what the App will run:
./bin/app aboutThe queue section shows the app queue name, driver, backend queue name, and worker count. For example, reports may show Queue Name: reports, Driver: redis, and Workers: 2.
Dispatching Work
Application services usually dispatch jobs through injected job types or queue dependencies.
Do not make HTTP controllers build raw queue payloads when a job type can own the payload shape and dispatch behavior.
When generating a job, pass --queue to stamp the generated dispatch helper:
forj make:job reports:generate --queue reportsWorkers
Start workers with:
forj worker
./bin/app workerWithout --queue, the worker process starts workers for every configured generated queue. To run only one queue:
forj worker --queue reports
./bin/app worker --queue reportsRepeat --queue to run a subset:
./bin/app worker --queue emails --queue reportsIn standalone local mode, workers can also be hosted with other enabled runtimes:
forj app
./bin/app runRegeneration
After changing supported drivers or named queues, use the normal build path:
forj buildDev Loop
During forj dev, the generated build watcher normally runs forj build for you.
Use focused generation only when you intentionally want to refresh queues without a full build:
forj generate --queueCommon Mistakes
Common mistakes
- Do not use events as a replacement for durable queued work.
- Do not dispatch unnamed or anonymous work in docs.
- Do not import backend queue driver packages in business services.
- Do not assume in-process queues behave like distributed queues.
- Do not forget to plan shutdown behavior for long-running workers.
