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

# Database backends

> For operators choosing between goleveldb and PebbleDB on a Cosmos Hub node, this page sets the backend, shows how to tell which one a data directory uses, and explains how to switch.

Commands on this page were run on gaia v28.3.1 (Cosmos SDK v0.53.4, CometBFT v0.38.23) on 2026-10-15 by agent testing on a local devnet.

gaia v28.3.1 stores the block store and the application state in an embedded key value database. Two backends are compiled in: goleveldb, the default, and PebbleDB. You choose once, before the first sync, because the two write different file formats. A node changes backend only by restoring a data directory written with the other one. This page assumes a node from [Join mainnet](https://docs.cosmos.network/hub/latest/hub-tutorials/join-mainnet.md).

## Which backends the binary has

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
gaiad version --long | grep -E 'cometbft-db@|cockroachdb/pebble@'
```

This prints `github.com/cometbft/cometbft-db@v1.0.4` and `github.com/cockroachdb/pebble@v1.1.5`. cometbft-db v1.0.4 registers the `pebbledb` backend unconditionally, so every v28.3.1 build has it, whichever install method you used. The `--db_backend` help text on `gaiad start` lists `goleveldb | cleveldb | boltdb | rocksdb | badgerdb` and omits pebbledb. The help string is stale, and the backend works. The `gaiad prune --help` output names the three app backends the Cosmos SDK side accepts: `goleveldb`, `rocksdb`, and `pebbledb`.

## Two settings, one choice

CometBFT and the application open their stores separately, so there are two keys. They must match.

**PebbleDB**

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
gaiad config set config db_backend pebbledb -s
gaiad config set app app-db-backend pebbledb
gaiad config get config db_backend
gaiad config get app app-db-backend
```

The `db_backend` key at the top of `config.toml` covers the CometBFT stores (`blockstore.db`, `state.db`, `tx_index.db`, `evidence.db`). The `app-db-backend` key in `app.toml` covers `application.db`. When it is empty the application falls back to `db_backend`, so setting both is redundant but safe. The `-s` flag is needed on the `config.toml` write, see [Join mainnet](https://docs.cosmos.network/hub/latest/hub-tutorials/join-mainnet.md). Then restore a PebbleDB snapshot from the [Sync a node](https://docs.cosmos.network/hub/latest/node/sync.md) table, or state sync into an empty data directory.

**goleveldb**

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
gaiad config set config db_backend goleveldb -s
gaiad config set app app-db-backend ""
gaiad config get config db_backend
```

These are the defaults written by `gaiad init`. Most snapshot providers still publish goleveldb archives, so this is the easiest path when you restore from one of them.

The settings are read at startup only. Changing them on a node with existing data does not convert anything. The node fails to open its stores, or opens empty ones and refuses to sync. Set them first. Then put the matching data in place. Then start.

## Tell which backend a data directory uses

Look at any store directory. The largest is `data/application.db`:

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
ls ~/.gaia/data/application.db | head
```

Both backends write `CURRENT` and `MANIFEST-<number>` files, so look past those. A PebbleDB directory has an `OPTIONS-<number>` file and stores tables as `*.sst`. A goleveldb directory stores tables as `*.ldb` and has no `OPTIONS-` file. A `LOG` file can appear in either directory (a goleveldb-configured open leaves one behind in a PebbleDB directory), so do not use it as the tell. A freshly created PebbleDB store on v28.3.1 contained `000002.log`, `CURRENT`, `LOCK`, `MANIFEST-000001`, and `OPTIONS-000003`. A goleveldb store contained `000002.ldb`, `000003.log`, `CURRENT`, `LOCK`, `LOG`, and `MANIFEST-000004`. Run the same check on a downloaded archive before extracting it, as shown on [Sync a node](https://docs.cosmos.network/hub/latest/node/sync.md).

## Why operators switch

PebbleDB is the backend that most of the current Hub snapshot providers who state a backend have moved to. It is also the one the Hub's own infrastructure work focuses on. The practical differences operators report are shorter compaction pauses on large stores and steadier disk throughput. The disk ratio between the two was not measured for this page, so do not plan capacity on a claimed saving. If your node is healthy on goleveldb, there is no requirement to switch.

## Switch an existing node

The only supported switch is to replace the data directory.

> [!WARNING]
>
> On a validator, keep `data/priv_validator_state.json` through the switch. It is the double sign guard. A reset replaces it with a fresh file at height 0. A restored archive replaces it with another node's copy. Either one removes the guard.

1. Stop the node and copy `~/.gaia/data/priv_validator_state.json` somewhere safe.
2. Set `db_backend` and `app-db-backend` to the target backend, as above.
3. Reset the data directory with `gaiad comet unsafe-reset-all --keep-addr-book`.
4. Restore a snapshot made with the target backend, or configure state sync, following [Sync a node](https://docs.cosmos.network/hub/latest/node/sync.md).
5. Put `priv_validator_state.json` back and start the node.

A validator should do this on a sentry or a standby machine first, then swap, so it never misses blocks while a 15 GB archive downloads.

## Prune offline

The `gaiad prune` command is meant to apply a pruning strategy to the application store while the node is stopped. On gaia v28.3.1 it does not work. Both `prune default` and `prune custom`, with or without `--app-db-backend`, panic before touching the store with `panic: failed to read genesis from file <home>: is a directory`. They panic because the prune command has no chain-id, and the gaia app falls back to reading the home directory as the genesis file. There is no workaround on this release. The `--chain-id` flag is not a `prune` flag, and `GAIAD_CHAIN_ID` is ignored. Should the command run at all, `prune custom` additionally requires `--pruning-interval`. Also, `--app-db-backend` must name your store because it assumes goleveldb otherwise.

Control history with the `pruning` setting in `app.toml` instead. Let the running node prune:

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
gaiad config set app pruning default
gaiad config get app pruning
```

This writes `pruning` in `app.toml` (`default`, `nothing`, `everything`, or `custom` with `pruning-keep-recent` and `pruning-interval`). It takes effect at the next start. To reclaim disk on a node that ran with `nothing` for a long time, restore a pruned snapshot as in [Switch an existing node](#switch-an-existing-node).

## Verify

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
gaiad config get config db_backend
gaiad config get app app-db-backend
ls ~/.gaia/data/application.db | grep -m 1 -E '^OPTIONS-|\.ldb$'
```

The two settings must name the same backend. The last command prints an `OPTIONS-` file for pebbledb or a `.ldb` file for goleveldb.

## Next

[Run gaiad as a service](https://docs.cosmos.network/hub/latest/node/service.md), or [Sync a node](https://docs.cosmos.network/hub/latest/node/sync.md) to put data in place.
