Library / SDK
allegro/bigcache avatar
allegro/bigcache

allegro/bigcache: a Go cache that keeps entries off the garbage collector's path

Efficient cache for gigabytes of data written in Go.

8,177 stars620 forksGoApache-2.0

At a glance

What is it?
BigCache stores byte slices in a sharded, evicting in-memory cache so that millions of entries do not slow down Go's garbage collector. It suits services holding many entries where GC pauses matter; it is a poor fit if you want typed values, iteration over live data, or a cache that frees memory back to the OS.
Who is it for?
Adopt bigcache if you run a Go service with read-heavy, byte-slice-shaped entries and you have measured GC pauses as the constraint; the v3 module path and a Config with Shards, LifeWindow and HardMaxCacheSize are all you need to start. Do not adopt it if you need typed values, live iteration, or memory returned to the OS on eviction, and do not treat it as a distributed cache next to Redis.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • allegro/bigcache8,177 ★ · +15
Star history
Repository2026-09-222026-11-14
allegro/bigcache8.2k8.2k

15 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The problem BigCache solves: heap entries that Go's GC has to walk

A plain map[string][]byte in a Go service with tens of millions of entries becomes a liability. Every key and every value is a pointer the garbage collector must trace during each cycle, and the pause grows with the number of live objects. BigCache's README states the design goal directly: it keeps entries on the heap but omits GC for them, which means operations on byte slices take place and entries need (de)serialization in front of the cache in most use cases.

That trade is the whole product. You give up typed values and get a cache whose contents the collector does not scan. The README points at the Go 1.5 optimization tracked in golang/go issue 9477 as the basis for this. The intended user is a Go service holding gigabytes of cached data where GC pause, not raw lookup speed, is the thing that hurts. A service caching a few thousand small structs has no reason to accept the serialization cost.

Shards, byte slices and why the cache cannot hand you a typed value back

The repository layout shows the mechanism: shard.go sits next to bigcache.go, and the Config struct exposes a Shards field documented as the number of shards, which must be a power of 2. Keys are hashed (fnv.go, hash.go) and routed to a shard, so concurrent writers contend on separate locks rather than one. That is where the parallel benchmark numbers in the README come from, though the README's own benchmark table is dated (go1.13, i7-6700K) and should be read as historical rather than as a claim about current hardware.

Values are bytes. The README's simple example passes []byte("value") to Set and receives a byte slice from Get, and it says serialization in front of the cache will be needed in most cases. There is no generic type parameter in the module path github.com/allegro/bigcache/v3. If your code wants a struct back, you own the encode and decode on both sides.

Two clocks govern lifetime, and the README is explicit that they are different things. LifeWindow is the time after which an entry can be called dead but not deleted. CleanWindow is the interval at which dead entries are actually removed; entries that still have life are not touched. Setting CleanWindow below one second is described as counterproductive because bigcache has a one second resolution.

Installing bigcache and running a first cache in Go

The module is published as github.com/allegro/bigcache/v3, and go.mod declares go 1.22, so a modern toolchain is expected even though the README still says Go 1.12 or newer is required. Fetch it with the standard module command:

bash
go get github.com/allegro/bigcache/v3

The README's simple initialization uses bigcache.DefaultConfig with a LifeWindow and a context, then Set and Get with byte slices. The value printed is the string form of the stored bytes:

go
import (
	"context"
	"fmt"
	"time"
	"github.com/allegro/bigcache/v3"
)

cache, _ := bigcache.New(context.Background(), bigcache.DefaultConfig(10 * time.Minute))
cache.Set("my-unique-key", []byte("value"))
entry, _ := cache.Get("my-unique-key")
fmt.Println(string(entry))

For a real service the README recommends custom initialization when the cache load can be predicted, because it avoids additional memory allocation. The fields that matter at that point are Shards (a power of 2), LifeWindow, CleanWindow, MaxEntriesInWindow (rps * lifeWindow, which the README says is used only in initial memory allocation) and MaxEntrySize, plus HardMaxCacheSize. A custom configuration looks like this:

go
config := bigcache.Config{
	Shards:             1024,
	LifeWindow:         10 * time.Minute,
	CleanWindow:        5 * time.Minute,
	MaxEntriesInWindow: 1000 * 10 * 60,
	MaxEntrySize:       500,
	Verbose:            true,
	HardMaxCacheSize:   8192,
}
cache, initErr := bigcache.New(context.Background(), config)
if initErr != nil {
	log.Fatal(initErr)
}

After that, Set and Get behave as in the simple example.

What happens when the cache is full, and other ways bigcache bites

The README says that when bigcache is full it can allocate additional memory for new entries instead of overwriting existing ones, as freecache does, and that a hard max size can be set with HardMaxCacheSize. Collisions are a separate way to lose data: BigCache does not handle them, so when a new item's hash collides with a stored item, the new item overwrites the previously stored value.

Memory reporting is the second trap. The README warns that system memory can appear to grow exponentially, and explains why: the Go runtime allocates memory in spans and marks them idle rather than returning them, so process resource usage stays high until the OS repurposes the address. A container memory limit set from a naive reading of RSS will kill the process for memory the cache no longer considers live.

Iteration is limited. iterator.go exists, but the README does not document iteration semantics, ordering, or whether deleted-but-unswept entries appear. Do not build a feature that depends on enumerating the cache until you have read that file. Finally, there is no persistence: restart the process and the cache is empty.

bigcache against freecache and a plain concurrent map

The README's own comparison set is bigcache, freecache and map, with benchmark source in a separate repository, allegro/bigcache-bench. On the numbers printed there, BenchmarkBigCacheSet-8 lands at 478 ns/op against 703 ns/op for BenchmarkFreeCacheSet-8, and the README concludes that writes and reads in bigcache are faster than in freecache. The GC pause comparison over 20 million entries reports 1.506077 ms for bigcache, 5.594416 ms for freecache and 9.347015 ms for map on amd64, with a much wider spread on arm64. The README itself concludes that bigcache and freecache have very similar GC pause time, which is a fair reading: freecache is the closer alternative in mechanism and intent, and the difference is in the access-path numbers rather than in collector behaviour.

The plain map is the honest baseline. It is fast for small working sets and needs no serialization, and the README notes that writes to map are the slowest of the three in its table. If your cache holds thousands of entries, use the map and skip the dependency. If it holds millions, the allocs and pause figures are the reason to move.

Redis and other out-of-process caches are a different category, not a substitute: bigcache lives in your process and disappears with it, so it cannot serve two replicas or survive a restart.

Licence, versioning and the cost of staying current

The repository is Apache-2.0, which permits commercial use and modification with the usual notice and attribution conditions; this is not legal advice, and if you redistribute a modified copy, read the LICENSE file at the repository root rather than this paragraph.

Version cadence deserves attention. The releases listed are v3.2.0 on 2026-08-14, v3.1.0 on 2022-11-04 and v3.0.2 on 2022-02-14. That is a nearly four-year gap between v3.1.0 and v3.2.0, so a team pinning to v3.1.0 has been running an old tag for a long time. Upgrade cost inside v3 should be small because the module path does not change, but the go.mod directive now reads go 1.22, and a project still building with an older toolchain will have to move its own go directive before it can take v3.2.0. The last push to the default branch was on 2026-10-12, so the repository is not dormant, but the release tags are the thing to watch, not commit activity.

Editorial conclusion

Adopt bigcache if you run a Go service with read-heavy, byte-slice-shaped entries and you have measured GC pauses as the constraint; the v3 module path and a Config with Shards, LifeWindow and HardMaxCacheSize are all you need to start. Do not adopt it if you need typed values, live iteration, or memory returned to the OS on eviction, and do not treat it as a distributed cache next to Redis. Before writing production code, verify three things in your own environment: that your values fit MaxEntrySize closely enough that the initial allocation is not wasted, that CleanWindow is at least one second because the resolution is one second, and that you can tolerate BigCache not handling hash collisions, since a colliding new item overwrites the stored value.

Frequently asked questions

What happens if my bigcache cache is full?

The README says that when bigcache is full it can allocate additional memory for new entries instead of overwriting existing ones, and that a hard max size can be set with HardMaxCacheSize.

How do I install and start using allegro/bigcache in a Go project?

Add the module with go get github.com/allegro/bigcache/v3, then call bigcache.New with either bigcache.DefaultConfig(lifeWindow) or a custom bigcache.Config. Set and Get take and return byte slices, so values usually need encoding and decoding around the cache.

What is the difference between LifeWindow and CleanWindow in bigcache?

The README defines LifeWindow as the time after which an entry can be called dead but not deleted, and CleanWindow as the interval after which dead entries are actually removed. Entries that still have life are not removed by a cleanup pass, and intervals below one second are counterproductive because the resolution is one second.

Does bigcache store typed values or only byte slices?

Only byte slices. The README's examples call Set with []byte("value") and print the result of Get as a string, and it notes that entries will need (de)serialization in front of the cache in most use cases.

Why does bigcache memory usage keep growing in system tools?

The README says this is expected: the Go runtime allocates memory in spans and marks them idle instead of returning them to the OS, so process resource usage stays elevated until the address is repurposed. It links to further reading on Go not freeing memory.

Official sources

  1. allegro/bigcache on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/allegro-bigcache.svg)](https://hysenlabs.com/projects/allegro-bigcache)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/allegro-bigcache.svg)](https://hysenlabs.com/projects/allegro-bigcache)

Was this useful?