# WorkerOptions Reference

Every bunqueue WorkerOptions field with its default: concurrency, batchSize, pollTimeout, heartbeatInterval, lockDuration, connection pooling and prefixKey.

Canonical: https://bunqueue.dev/guide/worker/options/

---

import { Tabs, TabItem } from '@astrojs/starlight/components';

<div class="bq-wrap bq-hero">
  <span class="bq-eyebrow">guide · worker</span>
  <h1 class="bq-hero-h1 bq-bench-h1">Every knob, <em>with its default.</em></h1>
  <p class="bq-hero-sub">The complete option surface for a Worker, what each one changes, and the defaults you get when you leave it alone.</p>
</div>

## Options reference

<Tabs syncKey="lang">
<TabItem label="Bun">

```typescript
const worker = new Worker('queue', processor, {
  embedded: true,
  concurrency: 5,
  batchSize: 100, // Pull up to 100 jobs per request
  pollTimeout: 5000, // Long-poll: wait up to 5s for jobs instead of busy polling
  limiter: { max: 10, duration: 1000 }, // Max 10 jobs per second
});
```

</TabItem>
<TabItem label="Node.js / Deno">

```typescript
const worker = new Worker('queue', processor, {
  embedded: false,
  concurrency: 5,
  batchSize: 100, // Pull up to 100 jobs per request
  pollTimeout: 5000, // Long-poll: wait up to 5s for jobs instead of busy polling
  limiter: { max: 10, duration: 1000 }, // Max 10 jobs per second
});
```

</TabItem>
<TabItem label="Python">

```python
worker = Worker(
    "queue",
    processor,
    concurrency=5,
    batch_size=100,        # Pull up to 100 jobs per request
    poll_timeout_ms=5000,  # Long-poll: wait up to 5s for jobs (default)
    lock_ttl_ms=30000,     # Job lease TTL
    ack_batch={"max_size": 50, "max_delay_ms": 5},  # Opt-in ACK batching
)
```

</TabItem>
<TabItem label="PHP">

```php
$worker = new Worker('queue', $processor, [
    'batchSize' => 100,           // Pull up to 100 jobs per request
    'pollTimeoutMs' => 5000,      // Long-poll: wait up to 5s for jobs (default)
    'lockTtlMs' => 30000,         // Job lease TTL
    'heartbeatIntervalS' => 10.0, // Heartbeats fire between jobs (sequential worker)
]);
```

</TabItem>
<TabItem label="Go">

```go
worker := bunqueue.NewWorker("queue", processor, bunqueue.WorkerOptions{
    Concurrency:        5,
    BatchSize:          100,   // Pull up to 100 jobs per request
    PollTimeoutMs:      5000,  // Long-poll: wait up to 5s for jobs (default)
    LockTtlMs:          30000, // Job lease TTL
    HeartbeatIntervalS: 10,    // Heartbeats are disabled by default in Go
})
```

</TabItem>
<TabItem label="Rust">

```rust
use std::time::Duration;
use bunqueue_client::{Worker, WorkerOptions};

let worker = Worker::new("queue", processor, WorkerOptions {
    concurrency: 5,
    batch_size: 100,        // Pull up to 100 jobs per request
    poll_timeout_ms: 5_000, // Long-poll: wait up to 5s for jobs (default)
    lock_ttl_ms: 30_000,    // Job lease TTL
    heartbeat_interval: Some(Duration::from_secs(10)),
    ..Default::default()
});
```

</TabItem>
<TabItem label="Elixir">

```elixir
worker =
  Bunqueue.Worker.new("queue", handler,
    concurrency: 5,
    batch_size: 100,          # Pull up to 100 jobs per request
    poll_timeout: 5_000,      # Long-poll: wait up to 5s for jobs
    lock_ttl: 30_000,         # Job lease TTL
    heartbeat_interval: 10_000
  )
```

</TabItem>
</Tabs>

The table below documents the shared TypeScript Worker options for Bun, Node.js, and Deno. Options for the other SDKs are tabulated in the [SDK guide](/guide/sdks/#worker-options).

| Option              | Type                                           | Default          | Description                                                                                                                                                                                                                         |
| ------------------- | ---------------------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `embedded`          | `boolean`                                      | `false`          | Use in-process mode                                                                                                                                                                                                                 |
| `concurrency`       | `number`                                       | `1`              | Parallel job processing                                                                                                                                                                                                             |
| `autorun`           | `boolean`                                      | `true`           | Start polling automatically                                                                                                                                                                                                         |
| `heartbeatInterval` | `number`                                       | `10000`          | Heartbeat interval in ms (0 = disabled)                                                                                                                                                                                             |
| `batchSize`         | `number`                                       | `10`             | Jobs to pull per batch (max: 1000)                                                                                                                                                                                                  |
| `batch`             | `{ size, minSize?, timeout?, groupAffinity? }` | -                | Native batch processor. `job.getBatch()` exposes members and `member.setAsFailed(error)` selectively fails one job. `minSize` waits indefinitely without `timeout`; grouped batches require `groupAffinity` to wait.                |
| `pollTimeout`       | `number`                                       | `0`              | Long-poll timeout in ms (max: 30000)                                                                                                                                                                                                |
| `useLocks`          | `boolean`                                      | `true`           | Enable BullMQ-style job locks                                                                                                                                                                                                       |
| `limiter`           | `{ max, duration, groupKey? }`                 | -                | Without `groupKey`: max job starts per rolling window, acquired atomically even with concurrent or manual processing. With `groupKey`: per-group concurrency cap of `max` (jobs grouped by `job.data[groupKey]`, `duration` unused) |
| `group`             | `{ concurrency?, limit?: { max, duration } }`  | unlimited / none | Broker-authoritative per-job-group concurrency and fixed-window rate defaults. See [Job Groups](/guide/queue/job-groups/)                                                                                                           |
| `lockDuration`      | `number`                                       | `30000`          | Job lock TTL in ms                                                                                                                                                                                                                  |
| `maxStalledCount`   | `number`                                       | `1`              | Accepted for BullMQ compatibility, but not applied by the Worker. Configure the broker's per-queue `maxStalls` policy with `Queue.setStallConfig()` or the HTTP API instead                                                         |
| `skipStalledCheck`  | `boolean`                                      | `false`          | In embedded or TCP mode, skip only this Worker's subscription to `stalled` notifications. It does not disable broker-side stall detection or recovery                                                                               |
| `skipLockRenewal`   | `boolean`                                      | `false`          | Suppress the per-job heartbeat timer entirely (no `JobHeartbeat` sent), so both lock renewal and broker-side stall freshness stop; only the worker-registration heartbeat keeps running                                              |
| `drainDelay`        | `number`                                       | `50`             | Delay between polls when the queue is empty (ms)                                                                                                                                                                                    |
| `removeOnComplete`  | `boolean \| number \| KeepJobs`                | `false`          | Auto-remove completed jobs. Only `true` is honored; `number` / `{ age?, count? }` are accepted for BullMQ type compatibility but ignored — the job's own `removeOnComplete` option still applies                                     |
| `removeOnFail`      | `boolean \| number \| KeepJobs`                | `false`          | Same behavior as `removeOnComplete`: only `true` is honored, other values are ignored and the job-level `removeOnFail` option still applies                                                                                                                                                                                  |
| `connection`        | `ConnectionOptions`                            | -                | TCP connection (`host`, `port`, `token`, `poolSize`)                                                                                                                                                                                |
| `prefixKey`         | `string`                                       | -                | Namespace prefix; must match the producing Queue's. See [Namespace Isolation](/guide/queue/advanced/#namespace-isolation-prefixkey)                                                                                                 |

**Connection pool sizing (TCP):** when `poolSize` is not set, it defaults to `min(concurrency, 8)`. Override it by setting `poolSize` explicitly.

| Embedded storage option | Type | Default | Description |
| --- | --- | --- | --- |
| `dataPath` | `string` | Unset | SQLite path for the process-wide embedded manager. Use the same path as the producing Queue. A conflicting path throws; TCP storage is configured on the server. |

If `dataPath` is omitted, the Worker uses the existing embedded manager or the
configured data-path environment variables. With neither a path nor a configured
manager, embedded storage is memory-only. See [Persistence](/guide/quickstart/#turn-on-persistence).

### Native batch option details

`batch.size` must be an integer from 1 through 1000. `minSize` defaults to 1,
must be no larger than `size`, and waits indefinitely when `timeout` is omitted
or zero. With a global Worker `limiter`, `minSize` must also be no larger than
`limiter.max`; `batch.size` may be larger and is processed in bounded chunks.
A positive `timeout` allows the available partial batch to start after that many
milliseconds. `groupAffinity: true` makes each processor batch homogeneous by
group ID; without affinity, batches containing grouped jobs do not wait for
`minSize`.

With native batching, `concurrency` counts processor invocations rather than
individual batch members. The leading job exposes every member through
`getBatch()`, and `setAsFailed(error)` marks one member for its own failure and
retry transition. A Worker `limiter` counts every member and reserves the whole
batch atomically only when it is ready; waiting for `minSize` consumes no rate
slots. Cancelling or timing out any member aborts the one shared processor
signal. See [Worker Concurrency and Batch Pulling](/guide/worker/concurrency/#native-processor-batches-bun).

:::caution[Worker options are not the queue's stall policy]
`maxStalledCount` and `skipStalledCheck` do not change when the broker recovers
an unresponsive job. Use the queue-level `stallInterval`, `maxStalls`,
`gracePeriod`, and `enabled` settings described in [Stall Detection](/guide/stall-detection/).
`skipLockRenewal`, by contrast, suppresses this Worker's per-job heartbeats
altogether — locks stop being renewed and the broker also stops seeing job
heartbeats for stall detection (even with `useLocks: false`) — so long-running
jobs can be marked stalled and redelivered.
:::

## Where to go next

| Guide | What it covers |
| ----------------------------------------------------------------------- | ----------------------------------------------- |
| [Worker](/guide/worker/)                                                | Create a worker and process your first job      |
| [Worker Concurrency and Batch Pulling](/guide/worker/concurrency/)      | Run jobs in parallel and pull them in batches   |
| [The Job Object Inside a Worker Processor](/guide/worker/job-object/)   | Everything the processor receives and can do    |
| [Worker Events](/guide/worker/events/)                                  | completed, failed, stalled and the rest         |
| [Worker Error Handling, Retries and Backoff](/guide/worker/errors/)     | Retries, backoff, timeouts and giving up        |
| [Worker Lifecycle](/guide/worker/lifecycle/)                            | Pause, resume and shut down without losing work |
| [Heartbeats, Stall Detection and Lock Ownership](/guide/worker/stalls/) | Heartbeats, stall recovery and lock ownership   |
| [SandboxedWorker](/guide/worker/sandboxed/)                             | Experimental isolation for CPU-heavy handlers   |