Connect to Tigerbeetle using Go

package main

import (
        "log"
        "os"

        tb "github.com/tigerbeetle/tigerbeetle-go"
        "github.com/tigerbeetle/tigerbeetle-go/pkg/types"
)

func main() {
        client, err := tb.NewClient(types.ToUint128(0), []string{"127.0.0.1:3000"})
        if err != nil {
                log.Printf("Error creating client: %s", err)
                os.Exit(1)
        }
        defer client.Close()

        log.Println("Successfully connected to TigerBeetle!")
}

This concise Go program serves as a minimal example of establishing a connection to TigerBeetle, a high-performance, distributed financial transactions database designed from the ground up for mission-critical safety and extreme throughput in online transaction processing (OLTP), particularly for double-entry accounting systems like debits and credits.

The program imports the standard log and os packages along with the official TigerBeetle Go client (github.com/tigerbeetle/tigerbeetle-go) and its types subpackage. In the main() function, it creates a new client instance using tb.NewClient, passing a cluster ID of 0 (converted to a 128-bit unsigned integer via types.ToUint128(0), as TigerBeetle uses 128-bit identifiers for safety and uniqueness) and a slice containing the address of a local TigerBeetle replica listening on port 3000 ("127.0.0.1:3000"—typically used for development or single-node setups).

If client creation fails (e.g., due to an unreachable server or invalid configuration), it logs the error and exits with status code 1. Upon success, a defer client.Close() ensures the client resources are properly released when the program terminates. Finally, it logs a simple confirmation message: “Successfully connected to TigerBeetle!”.

This program acts as a “hello world” for TigerBeetle integration in Go—verifying that the client can initialize and connect without performing any actual operations like creating accounts or transfers. It’s an ideal starting point for building more complex financial applications, showcasing the straightforward API while leveraging TigerBeetle’s strengths in consistency, durability, and massive scale for transactional workloads. Running it against a locally started TigerBeetle server (e.g., via ./tigerbeetle start --addresses=3000) will output the success message if the connection works.

For the purposes of this blog post, I will run TigerBeetle from a Docker image, using the following docker-compose.yaml file:

services:
  # Init container: Formats the data file
  tigerbeetle-init:
    image: ghcr.io/tigerbeetle/tigerbeetle:latest
    security_opt:
      - seccomp:unconfined
    cap_add:
      - IPC_LOCK
    ulimits:
      memlock:
        soft: -1
        hard: -1
    entrypoint: >
      sh -c "if [ ! -f /data/0_0.tigerbeetle ]; then
      ./tigerbeetle format --cluster=0 --replica=0 --replica-count=1 /data/0_0.tigerbeetle;
      echo 'Formatted data file.';
      else echo 'Data file already exists.'; fi"
    volumes:
      - ./data:/data

  # Main container: Runs the server
  tigerbeetle:
    image: ghcr.io/tigerbeetle/tigerbeetle:latest
    depends_on:
      tigerbeetle-init:
        condition: service_completed_successfully
    security_opt:
      - seccomp:unconfined
    cap_add:
      - IPC_LOCK
    ulimits:
      memlock:
        soft: -1
        hard: -1
    command: start --addresses=0.0.0.0:3000 /data/0_0.tigerbeetle
    ports:
      - "3000:3000"
    volumes:
      - ./data:/data

Save the file and execute docker-compose up before trying to run the Go program. When ready, save the Go code as connect.go and run the following:

$ go mod init
$ go mod tidy
$ go run connect.go
2026/01/02 07:10:29 Successfully connected to TigerBeetle!

Happy coding in Go!