Valkey cache provider
Valkey cache provider implementing cache.Provider against a single-node Valkey server, with tag-based invalidation and optional Valkey Search indexing.
Overview
Valkey is the BSD-3-Clause fork of Redis. It speaks the same wire protocol and supports the same commands, so for cache purposes it is a drop-in replacement. The provider wires a Valkey server into the piko cache port using the valkey-go client.
Wiring is two lines plus a config struct. The provider satisfies the cache.Provider port directly, so you register it with piko.WithCacheProvider and piko owns the rest of the lifecycle. Every namespace shares one valkey.Client, and each namespace becomes a key prefix, so adding caches costs no extra connections. The provider reuses piko's stampede protection and optimistic-locking compute machinery instead of reimplementing them.
Reach for Valkey when permissive licensing matters. Reach for Redis when you need feature parity with the latest Redis Stack modules. Reach for Valkey Cluster when you outgrow a single node, and for Otter when in-process speed matters more than cross-replica sharing.
crypto/tls.Config carries optional TLS settings. The Username field accepts a Valkey Access Control List (ACL) username. Leave it empty to use the default user. You must supply Registry.
The provider is pure Go with no build tags and no CGO. It runs unchanged in interpreted dev mode (dev-i) and in compiled builds.
Requirements
- A reachable Valkey server (single node, see Valkey Cluster for sharded deployments). Any Redis-compatible server (Redis OSS, Valkey, KeyDB) works at the protocol level.
- Network egress to the configured
Address. - A
cache.EncodingRegistrydescribing how to encode the value types you cache.
Configuration
import (
"os"
"time"
"piko.sh/piko/wdk/cache"
"piko.sh/piko/wdk/cache/cache_encoder_json"
"piko.sh/piko/wdk/cache/cache_provider_valkey"
)
jsonEncoder := cache_encoder_json.New[any]()
registry := cache.NewEncodingRegistry(jsonEncoder.(cache.AnyEncoder))
provider, err := cache_provider_valkey.NewValkeyProvider(cache_provider_valkey.Config{
Address: "localhost:6379", // required: host:port
Username: "", // ACL username; empty for default user
Password: os.Getenv("VALKEY_PASSWORD"), // empty for servers without authentication
DB: 0, // database number passed to SELECT
Namespace: "myapp:", // global key prefix
ClientName: "piko-app", // CLIENT SETNAME identifier
IndexPrefix: "index:", // search index prefix
DefaultTTL: 1 * time.Hour, // entry expiry; default 1 hour
OperationTimeout: 2 * time.Second, // standard ops; default 2s
Registry: registry, // required: value encoder registry
// TLSConfig: &tls.Config{...}, // optional: enable TLS
})
if err != nil {
return err
}
cache_encoder_json.New[any]() returns a typed EncoderPort[any]. NewEncodingRegistry takes an AnyEncoder, so assert the encoder to cache.AnyEncoder before you pass it.
NewValkeyProvider pings the server during construction and fails fast if it is unreachable or Registry is nil. The constructor fills any zero-valued timeout or limit with shared piko cache defaults. Only Address and Registry need a value. The TTL defaults to 1 hour, the operation timeout to 2 seconds, the atomic timeout to 5 seconds, and the bulk timeout to 10 seconds. The flush timeout defaults to 30 seconds, the search timeout to 5 seconds, the compute retries to 10, and the index prefix to index:.
AllowUnsafeFLUSHDB is off by default. With it off, InvalidateAll cannot run FLUSHDB, and the call returns an error when Namespace is empty. Enable it only when you own the whole database and accept that FLUSHDB deletes every key, not just cache keys. With a Namespace set, InvalidateAll scans and deletes that prefix instead.
Bootstrap
ssr := piko.New(
piko.WithCacheProvider("valkey", provider),
piko.WithDefaultCacheProvider("valkey"),
)
Caching custom types
The provider auto-handles a fixed set of key and value combinations, such as string keys with []byte, string, int, or any values. Cache a custom struct type and creation returns an error directing you to register a factory. Register a blueprint with cache.RegisterProviderFactory that calls cache_provider_valkey.ValkeyProviderFactory for your type before you create that namespace.
See also
Other cache providers:
- Redis, original Redis (post-licence-change).
- Valkey Cluster, sharded Valkey for horizontal scale.
- Redis Cluster, sharded Redis equivalent.
- Otter, in-process cache for single-instance setups.
- Multilevel, Otter L1 in front of a Valkey L2.
Cache encoders and transformers:
- JSON encoder, register with the value
Registry. - Gob encoder, Go-native encoding alternative.
- Crypto transformer, encrypt cached values.
- Zstd transformer, compress cached values.
Framework docs:
- How to use the cache, wiring the cache service end-to-end.
- Cache API reference, every type and method on the cache service.
- About caching, design rationale for the cache port.
External:
- Valkey project, official site, governance, and roadmap.
- valkey-go client, the underlying Go driver.