Skip to main content
In this Go quickstart you will learn how to:
  • Retrieve database credentials
  • Install the libSQL client
  • Connect to a remote Bunny Database
  • Execute a query using SQL

Quickstart

1

Retrieve database credentials

You will need an existing database to continue. If you don’t have one, create one.Navigate to Dashboard > Edge Platform > Database > [Select Database] > Access to find your database URL and generate an access token.
You should store these as environment variables to keep them secure.
2

Install libsql-client-go

Install the libSQL client package:
go get github.com/tursodatabase/libsql-client-go/libsql
3

Initialize a new client

Create a database connection with your database URL and auth token:
package main

import (
	"database/sql"
	"fmt"
	"os"

	_ "github.com/tursodatabase/libsql-client-go/libsql"
)

func main() {
	url := fmt.Sprintf("%s?authToken=%s",
		os.Getenv("DB_URL"),
		os.Getenv("DB_TOKEN"),
	)

	db, err := sql.Open("libsql", url)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to open db %s: %s", url, err)
		os.Exit(1)
	}
	defer db.Close()
}
4

Execute a query using SQL

You can execute a SQL query against your database using Query() for reads or Exec() for writes:
rows, err := db.Query("SELECT * FROM users")
if err != nil {
	fmt.Fprintf(os.Stderr, "failed to execute query: %v\n", err)
	os.Exit(1)
}
defer rows.Close()

for rows.Next() {
	var id int
	var name string
	if err := rows.Scan(&id, &name); err != nil {
		fmt.Fprintf(os.Stderr, "failed to scan row: %v\n", err)
		os.Exit(1)
	}
	fmt.Printf("id: %d, name: %s\n", id, name)
}

if err := rows.Err(); err != nil {
	fmt.Fprintf(os.Stderr, "error during iteration: %v\n", err)
	os.Exit(1)
}
If you need to use placeholders for values, you can do that:
rows, err := db.Query("SELECT * FROM users WHERE id = ?", 1)

Placeholders

libSQL supports the use of positional and named placeholders within SQL statements:
rows, err := db.Query("SELECT * FROM users WHERE id = ?", 1)
libSQL supports the same named placeholder characters as SQLite — :, @ and $.

Executing Writes

Use Exec() for INSERT, UPDATE, and DELETE statements:
result, err := db.Exec("INSERT INTO users (name) VALUES (?)", "Kit")
if err != nil {
	fmt.Fprintf(os.Stderr, "failed to insert: %v\n", err)
	os.Exit(1)
}

rowsAffected, _ := result.RowsAffected()
lastInsertId, _ := result.LastInsertId()

fmt.Printf("rows affected: %d, last insert id: %d\n", rowsAffected, lastInsertId)

Transactions

You can use transactions to execute multiple statements atomically:
tx, err := db.Begin()
if err != nil {
	fmt.Fprintf(os.Stderr, "failed to begin transaction: %v\n", err)
	os.Exit(1)
}

_, err = tx.Exec("INSERT INTO users (name) VALUES (?)", "Kit")
if err != nil {
	tx.Rollback()
	fmt.Fprintf(os.Stderr, "failed to insert: %v\n", err)
	os.Exit(1)
}

_, err = tx.Exec("INSERT INTO users (name) VALUES (?)", "Sam")
if err != nil {
	tx.Rollback()
	fmt.Fprintf(os.Stderr, "failed to insert: %v\n", err)
	os.Exit(1)
}

if err := tx.Commit(); err != nil {
	fmt.Fprintf(os.Stderr, "failed to commit: %v\n", err)
	os.Exit(1)
}

Prepared Statements

For repeated queries, you can use prepared statements for better performance:
stmt, err := db.Prepare("SELECT * FROM users WHERE id = ?")
if err != nil {
	fmt.Fprintf(os.Stderr, "failed to prepare statement: %v\n", err)
	os.Exit(1)
}
defer stmt.Close()

rows, err := stmt.Query(1)
if err != nil {
	fmt.Fprintf(os.Stderr, "failed to execute query: %v\n", err)
	os.Exit(1)
}
defer rows.Close()

Context Support

The libSQL client supports Go’s context for timeout and cancellation:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

rows, err := db.QueryContext(ctx, "SELECT * FROM users")
if err != nil {
	fmt.Fprintf(os.Stderr, "failed to execute query: %v\n", err)
	os.Exit(1)
}
defer rows.Close()