Caching in Go (Golang): Redis, in-memory and other solutions
Caching is one of the key strategies for improving performance and reducing database load in Go applications. In this article, we will cover the main approaches and libraries for implementing caching: from simple in-memory solutions to distributed caching based on Redis. You will learn when to choose which tool and how to properly organize caching in Go projects.
1. Built-in capabilities: map and sync.Map
The simplest way to cache in Go is using a regular map with a mutex or the thread-safe sync.Map. These approaches are suitable for small projects or prototypes where complex invalidation policies are not required.
Example with sync.Map:
package main
import ( "fmt" "sync")
type Cache struct { data sync.Map}
func (c *Cache) Set(key string, value interface{}) { c.data.Store(key, value)}
func (c *Cache) Get(key string) (interface{}, bool) { return c.data.Load(key)}
func main() { cache := &Cache{} cache.Set("user:1", "Alice") if val, ok := cache.Get("user:1"); ok { fmt.Println("Found:", val) }}Pros: simplicity, zero dependencies.
Cons: no TTL, no automatic cleanup, memory is not limited.
2. In-memory cache with TTL: freecache
Freecache is a fast in-memory cache library with TTL (time-to-live) support. It uses a segmented architecture to minimize locking and efficiently manages memory.
Installation:
go get github.com/coocood/freecacheUsage example:
package main
import ( "fmt" "github.com/coocood/freecache")
func main() { // Create a cache of 100 MB cache := freecache.NewCache(100 * 1024 * 1024)
// Set a value with a TTL of 10 seconds cache.Set([]byte("mykey"), []byte("myvalue"), 10)
// Get the value if val, err := cache.Get([]byte("mykey")); err == nil { fmt.Println("Value:", string(val)) } else { fmt.Println("Key not found or expired") }}Pros: automatic TTL cleanup, low CPU usage, support for large data volumes.
Cons: single-process only (not distributed).
3. BigCache — an alternative to freecache
BigCache is another popular in-memory library, optimized for storing a large number of entries (millions) with minimal access time. It also supports TTL and automatic eviction of old data.
Example:
package main
import ( "fmt" "github.com/allegro/bigcache/v3" "time")
func main() { config := bigcache.Config{ Shards: 1024, LifeWindow: 10 * time.Minute, CleanWindow: 5 * time.Minute, MaxEntriesInWindow: 1000 * 10 * 60, MaxEntrySize: 500, Verbose: true, }
cache, _ := bigcache.NewBigCache(config) cache.Set("mykey", []byte("bigcache value")) val, _ := cache.Get("mykey") fmt.Println(string(val))}Pros: high performance with a large number of keys, flexible configuration.
Cons: like freecache — local cache only.
4. Distributed caching with Redis and go-redis
For distributed systems where multiple application instances need a shared cache, Redis is used. The most popular client for Go is go-redis (formerly go-redis/redis).
Installation:
go get github.com/redis/go-redis/v9