Go language bindings for FoundationDB, a distributed key-value store with ACID transactions
npx @tessl/cli install tessl/golang-github-com-apple-foundationdb-bindings-go@7.3.0The FoundationDB Go bindings provide a comprehensive interface to FoundationDB, a distributed key-value database with multi-version concurrency control (MVCC) and ACID transactions. These bindings enable Go applications to leverage FoundationDB's strong consistency guarantees, automatic conflict resolution, and distributed architecture.
go get github.com/apple/foundationdb/bindings/go@v7.3.69import (
"github.com/apple/foundationdb/bindings/go/src/fdb"
"github.com/apple/foundationdb/bindings/go/src/fdb/tuple"
"github.com/apple/foundationdb/bindings/go/src/fdb/subspace"
"github.com/apple/foundationdb/bindings/go/src/fdb/directory"
)package main
import (
"fmt"
"log"
"github.com/apple/foundationdb/bindings/go/src/fdb"
)
func main() {
// Set API version (required before any other operations)
fdb.MustAPIVersion(730)
// Open the default database
db := fdb.MustOpenDefault()
defer db.Close()
// Perform a transaction
result, err := db.Transact(func(tr fdb.Transaction) (interface{}, error) {
// Write a key-value pair
tr.Set(fdb.Key("hello"), []byte("world"))
// Read a value
value := tr.Get(fdb.Key("hello")).MustGet()
return value, nil
})
if err != nil {
log.Fatalf("Transaction failed: %v", err)
}
fmt.Printf("Value: %s\n", string(result.([]byte)))
}The FoundationDB Go bindings are organized into four main packages:
The core package provides database connectivity, transaction management, and fundamental operations. It implements:
The tuple package provides encoding/decoding of multi-element tuples into FoundationDB keys while preserving sort order. This enables hierarchical key structures where keys can be composed of multiple typed elements (strings, integers, floats, booleans, UUIDs, etc.) that maintain proper lexicographic ordering.
The subspace package implements namespace management using tuple prefixes. Subspaces partition the keyspace into logical regions, enabling:
The directory layer provides hierarchical path-based organization of subspaces, similar to a filesystem. It automatically allocates short prefixes for each directory path, enabling:
Connect to FoundationDB clusters and manage database lifecycle.
// Open database using default cluster file
func OpenDefault() (Database, error)
func MustOpenDefault() Database
// Open database with specific cluster file
func OpenDatabase(clusterFile string) (Database, error)
func MustOpenDatabase(clusterFile string) Database
// Open database with connection string
func OpenWithConnectionString(connectionString string) (Database, error)
// Close database
func (d Database) Close()Execute ACID transactions with automatic retry logic for transient conflicts.
// Run transaction with automatic commit and retry
func (d Database) Transact(f func(Transaction) (interface{}, error)) (interface{}, error)
// Run read-only transaction
func (d Database) ReadTransact(f func(ReadTransaction) (interface{}, error)) (interface{}, error)
// Create manual transaction
func (d Database) CreateTransaction() (Transaction, error)
// Transaction operations
func (tr Transaction) Set(key KeyConvertible, value []byte)
func (tr Transaction) Get(key KeyConvertible) FutureByteSlice
func (tr Transaction) Clear(key KeyConvertible)
func (tr Transaction) Commit() FutureNil
func (tr Transaction) OnError(e error) FutureNilRead and write key-value pairs with support for atomic operations.
// Basic operations
func (tr Transaction) Get(key KeyConvertible) FutureByteSlice
func (tr Transaction) Set(key KeyConvertible, value []byte)
func (tr Transaction) Clear(key KeyConvertible)
func (tr Transaction) ClearRange(r Range)
// Atomic operations
func (tr Transaction) Add(key KeyConvertible, param []byte)
func (tr Transaction) BitAnd(key KeyConvertible, param []byte)
func (tr Transaction) BitOr(key KeyConvertible, param []byte)
func (tr Transaction) BitXor(key KeyConvertible, param []byte)
func (tr Transaction) Max(key KeyConvertible, param []byte)
func (tr Transaction) Min(key KeyConvertible, param []byte)
func (tr Transaction) CompareAndClear(key KeyConvertible, param []byte)Efficiently iterate over key ranges with configurable streaming modes.
// Get range of key-value pairs
func (tr Transaction) GetRange(r Range, options RangeOptions) RangeResult
// Range options
type RangeOptions struct {
Limit int // Maximum number of results (0 = unlimited)
Mode StreamingMode // Balances latency vs bandwidth
Reverse bool // Iterate in reverse order
}
// Iterate over results
func (rr RangeResult) Iterator() RangeIterator
func (ri RangeIterator) Advance() bool
func (ri RangeIterator) Get() (KeyValue, error)Encode and decode multi-element tuples into FoundationDB keys with sort order preservation.
// Create and pack tuples
type Tuple []TupleElement
func (t Tuple) Pack() []byte
func (t Tuple) FDBKey() Key
// Unpack tuples from keys
func Unpack(b []byte) (Tuple, error)
// Versionstamp support
func (t Tuple) PackWithVersionstamp(prefix []byte) ([]byte, error)
func IncompleteVersionstamp(userVersion uint16) VersionstampOrganize keys into namespaced regions using tuple prefixes.
// Create subspaces
func Sub(el ...TupleElement) Subspace
func FromBytes(b []byte) Subspace
func AllKeys() Subspace
// Subspace operations
type Subspace interface {
Sub(el ...TupleElement) Subspace
Pack(t Tuple) Key
Unpack(k KeyConvertible) (Tuple, error)
Contains(k KeyConvertible) bool
Bytes() []byte
}Organize subspaces hierarchically using filesystem-like paths.
// Access default root directory
func Root() Directory
// Create custom directory layer
func NewDirectoryLayer(nodeSS, contentSS Subspace, allowManualPrefixes bool) Directory
// Directory operations
type Directory interface {
CreateOrOpen(t Transactor, path []string, layer []byte) (DirectorySubspace, error)
Open(rt ReadTransactor, path []string, layer []byte) (DirectorySubspace, error)
Create(t Transactor, path []string, layer []byte) (DirectorySubspace, error)
Move(t Transactor, oldPath []string, newPath []string) (DirectorySubspace, error)
Remove(t Transactor, path []string) (bool, error)
Exists(rt ReadTransactor, path []string) (bool, error)
List(rt ReadTransactor, path []string) ([]string, error)
}
// Package-level convenience functions
func CreateOrOpen(t Transactor, path []string, layer []byte) (DirectorySubspace, error)
func Open(rt ReadTransactor, path []string, layer []byte) (DirectorySubspace, error)
func Create(t Transactor, path []string, layer []byte) (DirectorySubspace, error)Configure runtime behavior by selecting an API version.
// Set API version (must be called before any other fdb operations)
func APIVersion(version int) error
func MustAPIVersion(version int)
// Query API version
func GetAPIVersion() (int, error)
func IsAPIVersionSelected() boolSupported versions: 200-730
Isolate key spaces for multi-tenant applications.
// Tenant management
func (d Database) CreateTenant(name KeyConvertible) error
func (d Database) DeleteTenant(name KeyConvertible) error
func (d Database) OpenTenant(name KeyConvertible) (Tenant, error)
func (d Database) ListTenants() ([]Key, error)
// Tenant operations
type Tenant interface {
CreateTransaction() (Transaction, error)
Transact(f func(Transaction) (interface{}, error)) (interface{}, error)
ReadTransact(f func(ReadTransaction) (interface{}, error)) (interface{}, error)
GetName() Key
}FoundationDB errors are represented by the Error type, which contains an error code. The bindings support two error handling patterns:
Explicit Error Handling:
value, err := tr.Get(fdb.Key("mykey")).Get()
if err != nil {
return nil, err
}Panic-Based Error Handling (Recommended in Transactions):
// MustGet panics with fdb.Error, which Transact catches and handles
value := tr.Get(fdb.Key("mykey")).MustGet()The Transact and ReadTransact methods automatically catch panicked fdb.Error values and either retry the transaction (for retryable errors) or return the error to the caller (for fatal errors).
Many operations return Future objects that represent values available at a later time:
All Future types support:
Get() - Block until ready and return value/errorMustGet() - Block until ready and return value (panics on error)IsReady() - Check if ready without blockingBlockUntilReady() - Block until readyCancel() - Cancel the operationMultiple futures can be outstanding simultaneously, enabling parallel execution within a single goroutine.
Range queries support different streaming modes to balance latency and bandwidth:
ReadTransact for queries without mutationsTransact, MustGet is safer than explicit error checking