Status: Deferred post-v0.4 launch. The Go SDK has skeleton code in
sdks/go/
but is not functionally wired up yet. The API sketch below shows the
intended surface; treat it as a proposal, not an installable package.
For production use today, see the Rust, Python, or
TypeScript clients. If you need Go specifically, please
open an issue so we can prioritise it based on demand.
Build Kimberlite applications in Go with simplicity and performance.
Prerequisites (planned)
- Go 1.21 or later
- Running Kimberlite cluster (see Start)
Install (planned — not yet published)
Quick Verification
Create main.go:
package main
import (
"fmt"
kimberlite "github.com/kimberlitedb/kimberlite-go"
)
func main() {
fmt.Println("Kimberlite Go client imported successfully!")
fmt.Printf("Version: %s\n", kimberlite.Version)
}
Run it:
go run main.go
Sample Projects
Basic: Create Table and Query Data
package main
import (
"context"
"fmt"
"log"
kimberlite "github.com/kimberlitedb/kimberlite-go"
)
func main() {
ctx := context.Background()
client, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
})
if err != nil {
log.Fatal(err)
}
defer client.Close()
_, err = client.Exec(ctx, `
CREATE TABLE users (
id INT PRIMARY KEY,
email TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`)
if err != nil {
log.Fatal(err)
}
_, err = client.Exec(ctx,
"INSERT INTO users (id, email) VALUES (?, ?)",
1, "alice@example.com",
)
if err != nil {
log.Fatal(err)
}
rows, err := client.Query(ctx, "SELECT * FROM users")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var email string
var createdAt time.Time
if err := rows.Scan(&id, &email, &createdAt); err != nil {
log.Fatal(err)
}
fmt.Printf("User %d: %s\n", id, email)
}
}
Compliance: Enable RBAC and Test Access Control
package main
import (
"context"
"fmt"
"log"
kimberlite "github.com/kimberlitedb/kimberlite-go"
)
func main() {
ctx := context.Background()
adminClient, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
User: "admin",
Password: "admin-password",
})
if err != nil {
log.Fatal(err)
}
defer adminClient.Close()
_, err = adminClient.Exec(ctx, `
CREATE ROLE data_analyst;
GRANT SELECT ON patients TO data_analyst;
`)
if err != nil {
log.Fatal(err)
}
_, err = adminClient.Exec(ctx, `
CREATE USER analyst1
WITH PASSWORD 'analyst-password'
WITH ROLE data_analyst;
`)
if err != nil {
log.Fatal(err)
}
analystClient, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
User: "analyst1",
Password: "analyst-password",
})
if err != nil {
log.Fatal(err)
}
defer analystClient.Close()
rows, err := analystClient.Query(ctx, "SELECT * FROM patients")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
count := 0
for rows.Next() {
count++
}
fmt.Printf("Found %d patients\n", count)
_, err = analystClient.Exec(ctx,
"INSERT INTO patients VALUES (99, 'Unauthorized', '000-00-0000')",
)
if err != nil {
if kimberlite.IsPermissionDenied(err) {
fmt.Printf("Access denied: %v\n", err)
} else {
log.Fatal(err)
}
}
}
Multi-Tenant: Tenant Isolation Example
package main
import (
"context"
"fmt"
"log"
kimberlite "github.com/kimberlitedb/kimberlite-go"
)
func main() {
ctx := context.Background()
tenant1Client, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
TenantID: 1,
})
if err != nil {
log.Fatal(err)
}
defer tenant1Client.Close()
_, err = tenant1Client.Exec(ctx, `
CREATE TABLE orders (id INT, customer TEXT, amount DECIMAL);
INSERT INTO orders VALUES (1, 'Alice', 99.99);
`)
if err != nil {
log.Fatal(err)
}
tenant2Client, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
TenantID: 2,
})
if err != nil {
log.Fatal(err)
}
defer tenant2Client.Close()
rows, err := tenant2Client.Query(ctx, "SELECT * FROM orders")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
count := 0
for rows.Next() {
count++
}
fmt.Printf("Tenant 2 sees %d orders\n", count)
_, err = tenant2Client.Exec(ctx, "INSERT INTO orders VALUES (1, 'Bob', 149.99)")
if err != nil {
log.Fatal(err)
}
rows, err = tenant2Client.Query(ctx, "SELECT * FROM orders")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
count = 0
for rows.Next() {
count++
}
fmt.Printf("Tenant 2 sees %d orders\n", count) }
Compliance: Data Classification and Masking
package main
import (
"context"
"fmt"
"log"
kimberlite "github.com/kimberlitedb/kimberlite-go"
)
func main() {
ctx := context.Background()
client, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
})
if err != nil {
log.Fatal(err)
}
defer client.Close()
_, err = client.Exec(ctx, `
CREATE TABLE patients (
id INT PRIMARY KEY,
name TEXT NOT NULL,
ssn TEXT NOT NULL,
diagnosis TEXT
);
`)
if err != nil {
log.Fatal(err)
}
_, err = client.Exec(ctx,
"ALTER TABLE patients MODIFY COLUMN ssn SET CLASSIFICATION 'PHI'",
)
if err != nil {
log.Fatal(err)
}
_, err = client.Exec(ctx,
"ALTER TABLE patients MODIFY COLUMN diagnosis SET CLASSIFICATION 'MEDICAL'",
)
if err != nil {
log.Fatal(err)
}
_, err = client.Exec(ctx, `
INSERT INTO patients VALUES
(1, 'Alice Johnson', '123-45-6789', 'Hypertension'),
(2, 'Bob Smith', '987-65-4321', 'Diabetes');
`)
if err != nil {
log.Fatal(err)
}
_, err = client.Exec(ctx, "CREATE MASK ssn_mask ON patients.ssn USING REDACT")
if err != nil {
log.Fatal(err)
}
rows, err := client.Query(ctx, "SELECT * FROM patients")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name, ssn, diagnosis string
if err := rows.Scan(&id, &name, &ssn, &diagnosis); err != nil {
log.Fatal(err)
}
fmt.Printf("%s: SSN=%s\n", name, ssn) }
rows, err = client.Query(ctx, "SHOW CLASSIFICATIONS FOR patients")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var column, classification string
if err := rows.Scan(&column, &classification); err != nil {
log.Fatal(err)
}
fmt.Printf("%s: %s\n", column, classification)
}
}
Time-Travel: Query Historical State
package main
import (
"context"
"fmt"
"log"
"time"
kimberlite "github.com/kimberlitedb/kimberlite-go"
)
func main() {
ctx := context.Background()
client, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
})
if err != nil {
log.Fatal(err)
}
defer client.Close()
_, err = client.Exec(ctx, `
CREATE TABLE inventory (product_id INT, quantity INT);
INSERT INTO inventory VALUES (1, 100);
`)
if err != nil {
log.Fatal(err)
}
time.Sleep(2 * time.Second)
checkpoint := time.Now()
_, err = client.Exec(ctx, "UPDATE inventory SET quantity = 75 WHERE product_id = 1")
if err != nil {
log.Fatal(err)
}
rows, err := client.Query(ctx, "SELECT * FROM inventory WHERE product_id = 1")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
if rows.Next() {
var productID, quantity int
if err := rows.Scan(&productID, &quantity); err != nil {
log.Fatal(err)
}
fmt.Printf("Current quantity: %d\n", quantity) }
rows, err = client.Query(ctx,
"SELECT * FROM inventory AS OF TIMESTAMP ? WHERE product_id = 1",
checkpoint,
)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
if rows.Next() {
var productID, quantity int
if err := rows.Scan(&productID, &quantity); err != nil {
log.Fatal(err)
}
fmt.Printf("Historical quantity: %d\n", quantity) }
}
API Reference
Creating a Client
import kimberlite "github.com/kimberlitedb/kimberlite-go"
client, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
})
client, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
User: "username",
Password: "password",
})
client, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
TenantID: 1,
})
client, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
TLSEnabled: true,
TLSCACert: "/path/to/ca.pem",
})
client, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000", "localhost:3001", "localhost:3002"},
User: "admin",
Password: "password",
TenantID: 1,
TLSEnabled: true,
TLSCACert: "/path/to/ca.pem",
TLSClientCert: "/path/to/client.pem",
TLSClientKey: "/path/to/client-key.pem",
Timeout: 5 * time.Second,
MaxRetries: 3,
})
Executing Queries
_, err := client.Exec(ctx, `
CREATE TABLE products (
id INT PRIMARY KEY,
name TEXT NOT NULL,
price DECIMAL
)
`)
result, err := client.Exec(ctx,
"INSERT INTO products VALUES (?, ?, ?)",
1, "Widget", 19.99,
)
rowsAffected, _ := result.RowsAffected()
fmt.Printf("Inserted %d rows\n", rowsAffected)
Querying Data
rows, err := client.Query(ctx, "SELECT * FROM products")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
var price float64
if err := rows.Scan(&id, &name, &price); err != nil {
log.Fatal(err)
}
fmt.Printf("%s: $%.2f\n", name, price)
}
rows, err := client.Query(ctx,
"SELECT * FROM products WHERE price > ?",
25.0,
)
var count int
err := client.QueryRow(ctx, "SELECT COUNT(*) FROM products").Scan(&count)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Product count: %d\n", count)
Transactions
tx, err := client.Begin(ctx)
if err != nil {
log.Fatal(err)
}
_, err = tx.Exec(ctx, "UPDATE accounts SET balance = balance - 100 WHERE id = 1")
if err != nil {
tx.Rollback(ctx)
log.Fatal(err)
}
_, err = tx.Exec(ctx, "UPDATE accounts SET balance = balance + 100 WHERE id = 2")
if err != nil {
tx.Rollback(ctx)
log.Fatal(err)
}
if err := tx.Commit(ctx); err != nil {
log.Fatal(err)
}
Error Handling
import "github.com/kimberlitedb/kimberlite-go"
_, err := client.Exec(ctx, "INSERT INTO users VALUES (1, 'alice@example.com')")
if err != nil {
switch {
case kimberlite.IsConnectionError(err):
fmt.Println("Failed to connect to cluster")
case kimberlite.IsAuthenticationError(err):
fmt.Println("Invalid credentials")
case kimberlite.IsPermissionDenied(err):
fmt.Println("No permission for this operation")
case kimberlite.IsConstraintViolation(err):
fmt.Printf("Constraint violation: %v\n", err)
case kimberlite.IsQueryError(err):
fmt.Printf("Query error: %v\n", err)
default:
fmt.Printf("Error: %v\n", err)
}
}
Prepared Statements
stmt, err := client.Prepare(ctx,
"INSERT INTO logs (timestamp, message) VALUES (?, ?)",
)
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
_, err = stmt.Exec(ctx, time.Now(), "User logged in")
if err != nil {
log.Fatal(err)
}
_, err = stmt.Exec(ctx, time.Now(), "User logged out")
if err != nil {
log.Fatal(err)
}
Working with Types
import (
"database/sql"
"time"
"github.com/shopspring/decimal"
)
_, err := client.Exec(ctx, `
INSERT INTO transactions (id, amount, timestamp, metadata)
VALUES (?, ?, ?, ?)
`,
1,
decimal.NewFromFloat(99.99),
time.Now(),
`{"source": "web", "ip": "192.168.1.1"}`,
)
rows, err := client.Query(ctx, "SELECT * FROM transactions WHERE id = 1")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
if rows.Next() {
var id int
var amount decimal.Decimal
var timestamp time.Time
var metadata string
if err := rows.Scan(&id, &amount, ×tamp, &metadata); err != nil {
log.Fatal(err)
}
fmt.Printf("Amount: %s\n", amount)
fmt.Printf("Timestamp: %s\n", timestamp)
fmt.Printf("Metadata: %s\n", metadata)
}
Testing
Use the standard Go testing package:
package main
import (
"context"
"testing"
kimberlite "github.com/kimberlitedb/kimberlite-go"
)
func setup(t *testing.T) *kimberlite.Client {
ctx := context.Background()
client, err := kimberlite.Connect(ctx, &kimberlite.Config{
Addresses: []string{"localhost:3000"},
})
if err != nil {
t.Fatal(err)
}
rows, err := client.Query(ctx, "SHOW TABLES")
if err != nil {
t.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
t.Fatal(err)
}
_, err = client.Exec(ctx, "DROP TABLE IF EXISTS "+name)
if err != nil {
t.Fatal(err)
}
}
return client
}
func TestCreateTable(t *testing.T) {
client := setup(t)
defer client.Close()
ctx := context.Background()
_, err := client.Exec(ctx, `
CREATE TABLE test_table (
id INT PRIMARY KEY,
name TEXT NOT NULL
)
`)
if err != nil {
t.Fatal(err)
}
rows, err := client.Query(ctx, "SHOW TABLES")
if err != nil {
t.Fatal(err)
}
defer rows.Close()
found := false
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
t.Fatal(err)
}
if name == "test_table" {
found = true
break
}
}
if !found {
t.Error("Table test_table not found")
}
}
func TestInsertAndQuery(t *testing.T) {
client := setup(t)
defer client.Close()
ctx := context.Background()
_, err := client.Exec(ctx, "CREATE TABLE users (id INT, email TEXT)")
if err != nil {
t.Fatal(err)
}
_, err = client.Exec(ctx,
"INSERT INTO users VALUES (?, ?)",
1, "test@example.com",
)
if err != nil {
t.Fatal(err)
}
rows, err := client.Query(ctx, "SELECT * FROM users WHERE id = 1")
if err != nil {
t.Fatal(err)
}
defer rows.Close()
if !rows.Next() {
t.Fatal("Expected 1 row, got 0")
}
var id int
var email string
if err := rows.Scan(&id, &email); err != nil {
t.Fatal(err)
}
if email != "test@example.com" {
t.Errorf("Expected email 'test@example.com', got '%s'", email)
}
}
Examples
Complete example applications are available in the repository:
examples/go/basic/ - Simple CRUD application
examples/go/compliance/ - HIPAA-ready healthcare app
examples/go/multi-tenant/ - Multi-tenant SaaS application
examples/go/http/ - HTTP REST API with net/http
examples/go/grpc/ - gRPC service
Next Steps
Further Reading