Installation01
Install the core KV package:
go get github.com/xraph/grove/kvThen install the driver for your backend. This guide uses Redis:
go get github.com/xraph/grove/kv/drivers/redisdriverOther drivers are available as separate packages:
| Backend | Package |
| Redis | github.com/xraph/grove/kv/drivers/redisdriver |
| Memcached | github.com/xraph/grove/kv/drivers/memcacheddriver |
| DynamoDB | github.com/xraph/grove/kv/drivers/dynamodriver |
| BoltDB | github.com/xraph/grove/kv/drivers/boltdriver |
| Badger | github.com/xraph/grove/kv/drivers/badgerdriver |
Step 1: Connect and Open a Store02
Create a driver, connect it to the backend, and pass it to kv.Open:
package main
import (
"context"
"log"
"github.com/xraph/grove/kv"
"github.com/xraph/grove/kv/drivers/redisdriver"
)
func main() {
ctx := context.Background()
// Create the Redis driver and connect.
rdb := redisdriver.New()
if err := rdb.Open(ctx, "redis://localhost:6379/0"); err != nil {
log.Fatal(err)
}
// Open a Store backed by the Redis driver.
store, err := kv.Open(rdb)
if err != nil {
log.Fatal(err)
}
defer store.Close()
// Verify the connection.
if err := store.Ping(ctx); err != nil {
log.Fatal("cannot reach Redis:", err)
}
}Step 2: Basic Operations03
Set a value
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
user := User{Name: "Alice", Email: "[email protected]"}
err := store.Set(ctx, "user:1", &user)Get a value
var retrieved User
err := store.Get(ctx, "user:1", &retrieved)
if err != nil {
log.Fatal(err)
}
fmt.Println(retrieved.Name) // AliceDelete a key
err := store.Delete(ctx, "user:1")Check if a key exists
count, err := store.Exists(ctx, "user:1")
if count > 0 {
fmt.Println("key exists")
}Step 3: Using TTL04
Set a TTL (time-to-live) on a key to have it expire automatically:
import "time"
// Set with a 5-minute TTL.
err := store.Set(ctx, "session:abc", &sessionData, kv.WithTTL(5*time.Minute))
// Check remaining TTL.
ttl, err := store.TTL(ctx, "session:abc")
fmt.Println("expires in:", ttl)
// Update the TTL on an existing key.
err = store.Expire(ctx, "session:abc", 10*time.Minute)Step 4: Using Codecs05
By default, the Store uses JSON for serialization. You can switch to MsgPack for smaller payloads and faster encoding:
import "github.com/xraph/grove/kv/codec"
// Use MsgPack at the store level.
store, err := kv.Open(rdb, kv.WithCodec(codec.MsgPack()))The codec is applied transparently -- Get and Set calls work the same regardless of which codec is active. See the Codecs page for all built-in options and how to implement custom codecs.
Step 5: Conditional Writes06
Use WithNX to set a key only if it does not already exist (useful for distributed locks):
err := store.Set(ctx, "lock:resource", &lockData, kv.WithNX())
if errors.Is(err, kv.ErrConflict) {
fmt.Println("lock already held")
}Use WithXX to set a key only if it already exists (useful for updates):
err := store.Set(ctx, "user:1", &updatedUser, kv.WithXX())
if errors.Is(err, kv.ErrNotFound) {
fmt.Println("user does not exist")
}Complete Example07
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/xraph/grove/kv"
"github.com/xraph/grove/kv/codec"
"github.com/xraph/grove/kv/drivers/redisdriver"
)
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Role string `json:"role"`
}
func main() {
ctx := context.Background()
// Connect to Redis.
rdb := redisdriver.New()
if err := rdb.Open(ctx, "redis://localhost:6379/0"); err != nil {
log.Fatal(err)
}
// Open store with MsgPack codec.
store, err := kv.Open(rdb, kv.WithCodec(codec.MsgPack()))
if err != nil {
log.Fatal(err)
}
defer store.Close()
// Set with TTL.
user := User{Name: "Alice", Email: "[email protected]", Role: "admin"}
if err := store.Set(ctx, "user:1", &user, kv.WithTTL(24*time.Hour)); err != nil {
log.Fatal(err)
}
// Get.
var retrieved User
if err := store.Get(ctx, "user:1", &retrieved); err != nil {
log.Fatal(err)
}
fmt.Printf("Name: %s, Role: %s\n", retrieved.Name, retrieved.Role)
// Check TTL.
ttl, _ := store.TTL(ctx, "user:1")
fmt.Printf("Expires in: %s\n", ttl)
// Delete.
if err := store.Delete(ctx, "user:1"); err != nil {
log.Fatal(err)
}
}Next Steps08
Store Interface→
Full API reference for every Store method, including Batch, Scan, and Set options.
Keyspaces→
Type-safe, namespaced key partitions with automatic prefix and TTL management.
Codecs→
JSON, MsgPack, Protobuf, Gob, and custom codec implementation.
KV Overview→
Architecture, supported backends, and the full feature set.