# Choosing batteries and adapters

A decision guide for picking the adapter behind each battery, from zero-infrastructure defaults to production backends.

Every battery is one small interface with several adapters, and switching adapters is a config change, not a code change. So the question is never "which library do I commit to" but "which adapter fits this stage". Start on the zero-infrastructure defaults, then change one `adapter:` line when the deployment shape demands it.

The default for every battery in `config.Default()` runs with no external service (`memory`, `local`, `sqlite`, `log`, `noop`, ...), which is why tests and `zever serve` work on a fresh checkout. The full table is in the [adapters matrix](https://zenta-dev.github.io/zever/reference/adapters-matrix/); this page covers the choices that matter.

## The one rule

Pick by where state lives and who must see it:

- **One process, throwaway state** (tests, local dev, a single binary): the `memory` adapter.
- **Several processes must share the state** (more than one server replica, or server plus worker): an adapter backed by a shared service, `redis` or your `postgres` database.
- **You want fewer moving parts**: the `db` adapter that reuses the database you already run, instead of adding Redis.

## Common choices

| Battery | Local and tests | Production when... | Notes |
|---|---|---|---|
| `db` | `sqlite` (pure Go, no cgo) | `postgres` for anything multi-instance or write-heavy. | sqlite `:memory:` is per connection; use a file path under `t.TempDir()` in tests. |
| `cache` | `memory` | `redis` for a shared cache; `db` if you run no Redis. | `memory` is per process, so replicas see different values. |
| `queue` | `memory` | `redis` for separate worker tiers; `db` for a shared queue without Redis. | Only `redis` and `db` let another host pop. See [Queue](https://zenta-dev.github.io/zever/guides/background/queue/). |
| `session` | `memory` | `redis` or `db` so a session survives restarts and spans replicas. | |
| `auth` | `jwt` | `jwt` for stateless APIs; `session` for cookie apps; `oidc` to verify tokens from an identity provider. | `jwt` needs a secret of at least 32 bytes. |
| `ratelimit` | `memory` | `redis` when limits must hold across replicas. | |
| `lock`, `idempotency` | `memory` | `redis` (or `db` for idempotency) for cross-instance correctness. | |
| `eventbus` | `memory` | `redis` for fan-out across instances. | No durability for offline handlers. |
| `outbox` | `memory` | `db` for transactional delivery; `cdc` for postgres logical replication. | Defaults to `db`. |
| `scheduler` | `embedded` | `postgres` for durable leased slots on several hosts. | |
| `observability` | `stdout` | `otlp` to a collector. | `noop` for tests. |
| `log` | `slog` or `pretty` | `slog` or `zerolog` for JSON logs; `noop` in tests. | |
| `storage` | `local` | `s3` or `r2` for object storage. | |
| `search`, `vectorstore` | `db` | `meilisearch`, `postgres`, `pgvector`, or `qdrant` when scale or features demand it. | Start on `db`. |
| `secrets` | `env` | `vault` when you need rotation or an audited store. | `env` cannot rotate without a restart. |
| `permission` | `noop` | `rbac` or `casbin` when you enforce authorization. | |
| `router` | `stdhttp` | `stdhttp` or `fiber`. | Pick by the middleware ecosystem you want. |

## Decide in order

1. **Do I run more than one process of this service?** If no, stay on `memory`/`sqlite`. If yes, move the shared batteries (`session`, `ratelimit`, `lock`, `idempotency`, `cache`, `queue`) to `redis` or `db`.
2. **Do I already run Redis?** If yes, use it for the shared batteries. If no, the `db` adapters avoid adding a service at the cost of polling and database load.
3. **Does it carry money, auth, or compliance?** Do not use `stub`, `noop`, or `memory` adapters for it. The `stub` payment and billing adapters verify nothing and hold no funds.
4. **Do I need to read the choice back later?** Run `zever doctor` after changing config: it resolves every enabled battery and reports `OK` or `FAIL` per battery.

## Wiring a choice

Set it via env var (e.g., `CACHE_ADAPTER=redis`), and make sure the adapter is registered. `zever add cache/redis` adds the `go.mod` require, the `Register()` call, the wiring.go entry, and the `.env.example` stanza in one step:

```sh
zever add cache/redis
zever doctor
```

An enabled battery whose adapter was never registered fails at startup with a did-you-mean hint instead of at first use. To trim a binary to only the adapters you ship, see `zever build --adapters` in the [CLI reference](https://zenta-dev.github.io/zever/reference/cli/).

- [Adapters matrix](https://zenta-dev.github.io/zever/reference/adapters-matrix/): Every battery and adapter.
- [Providers and adapters](https://zenta-dev.github.io/zever/concepts/providers-adapters/): How registration and resolution work.
- [Write a plugin](https://zenta-dev.github.io/zever/guides/extend/write-a-plugin/): Bring your own adapter.
