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
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.
Install libsql-client-go
Install the libSQL client package:go get github.com/tursodatabase/libsql-client-go/libsql
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()
}
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()