> ## Documentation Index
> Fetch the complete documentation index at: https://getconvoy.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Postgres Queue

By default Convoy enqueues delivery work in Redis (Asynq), and Redis also holds cache, rate limits, and circuit breaker state. On a paid license you can set the queue provider to Postgres instead. That switch moves the **task queue, cache, rate limits, and circuit breaker** into Postgres. Redis is not required in that mode.

<Note>
  The Postgres task queue is **experimental**. Redis remains the default. Behaviour and operational characteristics can still change.
</Note>

## When to use it

Stay on Redis for production unless you are trying the experimental Postgres path on purpose.

Use Postgres when you want one datastore for durable jobs, cache, and limiter state, or when Redis memory for the backlog is the pain and Postgres is already sized for the event tables.

## Enable it

You need a paid license that includes the Postgres queue, and the `postgres-queue` feature flag (`CONVOY_ENABLE_FEATURE_FLAG` or `--enable-feature-flag`). Then set the provider to `postgres` in config or the environment. Restart **server** and **agent** so both enqueue and consume from the same backend.

```json queue_provider in convoy.json theme={null}
{
  "queue_provider": "postgres"
}
```

```shell CONVOY_QUEUE_PROVIDER theme={null}
export CONVOY_QUEUE_PROVIDER=postgres
```

Without the license or the flag, the process refuses to start with that provider set. Redis DSN is not required when the provider is Postgres.

Optional tuning (ignored unless the provider is `postgres`):

| JSON                                   | Environment                                   | Default |
| -------------------------------------- | --------------------------------------------- | ------- |
| `queue.postgres.batch_size`            | `CONVOY_POSTGRES_QUEUE_BATCH_SIZE`            | 64      |
| `queue.postgres.batch_wait_ms`         | `CONVOY_POSTGRES_QUEUE_BATCH_WAIT_MS`         | 2       |
| `queue.postgres.claim_batch_size`      | `CONVOY_POSTGRES_QUEUE_CLAIM_BATCH_SIZE`      | 64      |
| `queue.postgres.lease_timeout_seconds` | `CONVOY_POSTGRES_QUEUE_LEASE_TIMEOUT_SECONDS` | 90      |
| `queue.postgres.poll_idle_ms`          | `CONVOY_POSTGRES_QUEUE_POLL_IDLE_MS`          | 5       |
| `queue.postgres.write_concurrency`     | `CONVOY_POSTGRES_QUEUE_WRITE_CONCURRENCY`     | 8       |

Because the cache now shares the database with your event tables, each replica can
answer part of it from memory:

| JSON                               | Environment                               | Default |
| ---------------------------------- | ----------------------------------------- | ------- |
| `cache.postgres.local_read_ttl_ms` | `CONVOY_POSTGRES_CACHE_LOCAL_READ_TTL_MS` | 1000    |
| `cache.postgres.local_read_size`   | `CONVOY_POSTGRES_CACHE_LOCAL_READ_SIZE`   | 10000   |

An invalidation applies at once on the replica that made it, and within
`local_read_ttl_ms` on the others, so keep that window well below the TTLs of the
objects being cached. Set it to a negative value to send every read to the table.

See [Configuration](/docs/deployment/configuration) for the full `queue` and `cache` objects.

## What does not change

* Ingest HTTP APIs and brokers stay the same.
* Retry policy, circuit breaking, and rate limits behave the same. Their state lives in Postgres instead of Redis.
* Prometheus queue series names stay the same. When metrics are on, gauges come from a snapshot worker rather than a live scan of every delivery row. See [Metrics](/docs/product-manual/metrics#queue-depth-and-backlog-redis-and-postgres).

## Operations

* Every server and agent replica must use the same `queue_provider`. Do not mix Redis and Postgres consumers on one instance.
* Switching provider does not migrate in-flight Redis jobs into Postgres. Drain or accept that those Redis tasks are left behind before you flip.
* Size Postgres for the extra write load. The delivery tables and the job queue share the same database.

For Redis HA when the queue stays on Redis, see [Redis & Redis Sentinel](/docs/deployment/redis-and-sentinel).
