Skip to content
Pure Go · CGO_ENABLED=0 · wire-compatible with Java Record Layer 4.12.11.0

FoundationDB for Go

A from-scratch FoundationDB client in pure Go — no cgo, 2–4× faster reads than libfdb_c. Plus a wire-compatible Record Layer and SQL engine, so Go and Java services share one cluster, byte-for-byte.

Get started →    Star on GitHub
import "fdb.dev/pkg/fdbgo/fdbclient" // pure Go. CGO_ENABLED=0. static binary.

db, _ := fdbclient.Open("/etc/foundationdb/fdb.cluster")

Pre-1.0, built in the open. The wire format is the hard line — conformance- and differential-tested against the Java reference. Pin a commit and run the suites before production. Maturity →

No cgo. Static binary. Faster reads.

Most FDB tooling links Apple’s C library through cgo — no static binaries, painful cross-compilation, a glibc dependency. The pure-Go client speaks the FoundationDB wire protocol directly and is the default backend, producing byte-identical reads and writes. The Go runtime skips the C client’s network-thread hop and multi-version-client shim; writes share the same commit path and run at parity.

pure-Go vs libfdb_c · bar length = speedup
Get 100 B
60 vs 218 µs
3.6×
Get 1 KB
61 vs 209 µs
3.4×
GetRange 100 keys
92 vs 363 µs
3.9×
Read @ 10 ms RTT
5.3 vs 12.6 ms
2.4×
Set + Commit
1.01 vs 1.00 ms
1.0×

The 10 ms-RTT row is the realistic signal — localhost microbenchmarks are syscall/IPC-bound, so they're the optimistic end. The read advantage holds under real latency (2.4× at 10 ms) and converges to parity at extreme RTT, where both clients are network-bound. Writes run at parity. Reproducible from TestBenchmarkSanity; method in PERFORMANCE.md. Prefer Apple's C client? One build tag (-tags libfdbc) swaps it in — same bytes on the wire.

Quickstart

Install the driver, then open a database, create a schema, and read and write — all from Go. The pure-Go client is the default backend; you only need a cluster file.

Install

go get fdb.dev/pkg/relational/sqldriver

Open a database, create a schema, write and read — in Go

package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "fdb.dev/pkg/relational/sqldriver"
)

func main() {
	db, err := sql.Open("fdbsql",
		"fdbsql:///myapp?cluster_file=/etc/foundationdb/fdb.cluster&schema=main")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// Create the database, a schema template, and a schema.
	db.Exec(`CREATE DATABASE /myapp`)
	db.Exec(`CREATE SCHEMA TEMPLATE app
	    CREATE TABLE users (id BIGINT, name STRING, email STRING, PRIMARY KEY (id))
	    CREATE INDEX by_email ON users (email)`)
	db.Exec(`CREATE SCHEMA /myapp/main WITH TEMPLATE app`)

	// Write a row, then read it back.
	db.Exec(`INSERT INTO users (id, name, email) VALUES (1, 'Alice', 'alice@example.com')`)

	var name string
	if err := db.QueryRow(
		`SELECT name FROM users WHERE email = ?`, "alice@example.com",
	).Scan(&name); err != nil {
		log.Fatal(err)
	}
	fmt.Println(name) // Alice
}

Or query the same data from the CLI

$ frl sql --database /myapp --schema main
fdb> SELECT name, email FROM users WHERE email = 'alice@example.com';
NAME  │ EMAIL
──────┼───────────────────
Alice │ alice@example.com
(1 row)

The Cascades planner picks the by_email index for that query — no full scan. The same store is reachable from Go's typed record API (store protobuf records directly); see the record-layer guide.

A client, and layers on top.

FoundationDB is an ordered, transactional key-value store — strict-serializable ACID, fault-tolerant, proven by deterministic simulation testing. It’s the storage substrate under systems like Snowflake and Apple’s CloudKit. Higher-level data models are built as layers on top. fdb.dev is the Go client and a growing set of them.

Share a cluster with Java.

Wire compatibility is the project’s hard line, not a feature. Record, index, version, continuation, and split-record formats are byte-identical to Java Record Layer 4.12.11.0, and the client speaks the FoundationDB 7.3 wire protocol (validated against 7.3.77; 8.0 is future work). Enforced in CI against real FoundationDB by a Java conformance suite, a cross-backend differential, and a binding-stress tester — not mocks.

Get started →