# Pogreb: an embedded Go key-value store for point lookups

> Pogreb is an Apache-2.0 embedded key-value store written in Go for read-heavy applications and larger-than-memory data sets. Its hash-based design favors random reads while ruling out range scans and making large-database recovery potentially expensive.

**akrylysov/pogreb** — Embedded key-value store for read-heavy workloads written in Go

- Repository: https://github.com/akrylysov/pogreb
- Stars: 1,355 · Forks: 95
- Language: Go
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/akrylysov-pogreb

## Why Pogreb targets embedded point lookups

Pogreb addresses a narrower storage problem than a general-purpose database server. It is intended for applications that keep key-value data inside a Go process, retrieve records by exact key and perform writes less frequently than reads. The README describes it as an embedded store for read-heavy workloads and identifies fast random lookups and infrequent bulk inserts as its intended pattern.

That workload profile matters because Pogreb uses a hash table for indexing. A hash table is a natural fit when the common request is a lookup using a complete key. The indexing design can focus on that operation instead of maintaining sorted keys. It does not preserve the key ordering needed to locate a lower and upper bound efficiently. The README therefore identifies range scans as unsupported.

The likely user is a Go engineer embedding storage inside a service, command-line tool or batch process. Pogreb may also fit a workload whose data set is larger than available memory. It is not a direct substitute for a relational database or an ordered key-value database when the application depends on SQL queries, range predicates, secondary indexes or transactions across multiple records. The README does not claim those capabilities.

The embedded shape also differs from a client-server database. The documented API opens a local path through `pogreb.Open()` and exposes methods directly on `DB`. No remote client, network protocol, authentication mechanism or separate database service is described. Applications expecting those facilities would need another system or an additional service layer that the repository does not document.

## How Pogreb indexes WAL segments

The repository separates indexing, data logging, segments, compaction, recovery, backup, iteration and locking into separate Go files. That layout reflects a design built around direct key retrieval rather than an in-memory map alone.

According to the README, Pogreb has a single hash table shared across all WAL segments. WAL segments hold the write-ahead data, while the shared hash table supports point lookups. The README also explains that this arrangement affects recovery. Rebuilding the index may require processing all segments instead of reconstructing only a recent portion of the store.

This produces a clear trade-off. A hash index fits the targeted lookup workload, but its recovery path may scale with total database size. The README calls rebuilding the entire index potentially impractical for large databases. A service with a strict startup budget would therefore need to measure restart behavior with a representative data set rather than assuming that recovery cost is limited by the amount of recent writing.

The repository contains `options.go`, `metrics.go`, `backup.go` and `compaction.go`, but the README does not document their configuration keys or operational semantics. It also does not specify segment sizes, compaction triggers, backup consistency or temporary disk requirements. The linked `docs/design.md` is the documented place to investigate those internals. Without those details, the hash-index description is enough to evaluate the principal architectural boundary, but not enough to predict every production behavior.

## Installing Pogreb and running a first lookup

The README installs Pogreb as a Go module. This command adds the documented module to the current project environment:

```bash
$ go get -u github.com/akrylysov/pogreb
```

The repository's `go.mod` declares Go 1.18 and uses `github.com/akrylysov/pogreb` as its module path. A first program can open a local database, store one key-value pair and read it back. This example follows the API shown in the README:

```go
package main

import (
    "log"

    "github.com/akrylysov/pogreb"
)

func main() {
    db, err := pogreb.Open("pogreb.test", nil)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    if err := db.Put([]byte("testKey"), []byte("testValue")); err != nil {
        log.Fatal(err)
    }
    val, err := db.Get([]byte("testKey"))
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("%s", val)
}
```

`pogreb.Open()` opens or creates the named database. The README passes `nil` for the second argument without documenting its exact type or defaults. `DB.Put()` accepts byte slices for both the key and value. `DB.Get()` returns the bytes associated with the supplied key, while `DB.Close()` releases the database during function shutdown.

The expected log output is `testValue` for this example. The README states that all database methods are safe for concurrent use by multiple goroutines. It does not provide concurrency measurements, document compound-operation isolation or explain how contention affects simultaneous reads and writes, so those behaviors require direct project-level testing before adoption.

## Deleting records and traversing all Pogreb items

A record can be removed through `DB.Delete()`. The call reports any failure to the caller:

```go
err := db.Delete([]byte("testKey"))
if err != nil {
    log.Fatal(err)
}
```

Pogreb also exposes an `ItemIterator` through `DB.Items()`. Iteration ends when `Next()` returns `pogreb.ErrIterationDone`; other errors require separate handling. The documented loop is:

```go
it := db.Items()
for {
    key, val, err := it.Next()
    if err == pogreb.ErrIterationDone {
        break
    }
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("%s %s", key, val)
}
```

This operation visits stored items, but it should not be confused with a range scan. The README explicitly says the hash-table index makes range scans impossible. It also does not promise sorted output, a stable snapshot during concurrent writes or constant memory use while returning values.

These omissions limit what can be concluded about export, backup-adjacent processing and modification during iteration. A caller that writes or deletes while iterating may need synchronization beyond ordinary goroutine safety. The `iterator.go`, `backup.go` and design document are the relevant sources for those semantics. The README gives the control flow for iteration, but not enough detail to adopt it as an online query facility.

For bulk work, the stated workload is infrequent bulk insertion. Pogreb can write entries through `DB.Put()`, yet the README does not define a bulk-load API, transaction boundary or documented throughput. If ingestion speed dominates the application, its suitability depends on behavior that must be checked in the implementation rather than inferred from the embedded API.

## Pogreb recovery, upgrades and Bolt alternative

Recovery is the most concrete maintenance concern stated in the README. Because one hash table spans all WAL segments, opening a database may require rebuilding the entire index. The README warns that this can be impractical for large databases. An operator should establish the maximum acceptable startup time and compare it with recovery on production-sized files. A small example cannot represent that cost.

The repository includes `recovery.go` and `compaction.go`, confirming that both are separate implementation concerns. The README does not document recovery progress, compaction triggers, crash recovery guarantees or tuning controls. It also does not explain whether obsolete segment files are reclaimed immediately or how disk usage changes after large deletions. Those details affect capacity planning and incident handling.

The last repository push was on 2026-04-06. The latest listed release is `v0.10.2`, dated 2023-12-10, and earlier listed releases are `v0.10.1` from 2021-05-01 and `v0.10.0` from 2021-02-10. The repository is not archived. A newer push does not by itself document a stable release cadence, and the README does not describe file-format migrations or an upgrade procedure. Review `CHANGELOG.md` and test restoration from a copy of the real database format before changing versions.

Pogreb uses a shared hash table for point lookups and cannot perform range scans. A workload dominated by exact-key reads can match Pogreb's stated design, while a workload requiring ordered traversal may need to examine other embedded stores separately. The README mentions `bolt` in its benchmark context, but it does not provide reproducible benchmark numbers or describe Bolt's implementation.

Pogreb is distributed under Apache-2.0. The repository includes a `LICENSE` file, which should govern compliance, notice handling and redistribution. That statement identifies the declared license and does not replace review of the license text for a particular deployment.

## Conclusion

Pogreb fits Go services that need embedded random reads, larger-than-memory storage and infrequent bulk writes. It is a poor fit for ordered range queries or databases requiring inexpensive recovery after large WAL changes. Before adoption, verify recovery time at the expected database size, compaction behavior and the operational implications of embedding the database inside the service.

## FAQ

### How do I install Pogreb in a Go project?

The README documents `go get -u github.com/akrylysov/pogreb`. The repository's `go.mod` declares Go 1.18.

### Does Pogreb support range scans?

No. The README says that using a hash table for indexing makes range scans impossible.

### Is Pogreb safe to use from multiple goroutines?

Yes. The README states that all database methods are safe for concurrent use by multiple goroutines.

## Sources

- [akrylysov/pogreb on GitHub](https://github.com/akrylysov/pogreb)
- [Issues](https://github.com/akrylysov/pogreb/issues)
- [License: Apache-2.0](https://github.com/akrylysov/pogreb/blob/main/LICENSE)
- [README](https://github.com/akrylysov/pogreb/blob/main/README.md)
- [Releases](https://github.com/akrylysov/pogreb/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/akrylysov-pogreb
