⌘K ctrl+k
Search Shortcut cmd + k | ctrl + k
Go Client

The latest stable release of the DuckDB Go client bundles DuckDB 1.5.5. Its own version tag encodes that DuckDB version; see Versioning below.

The DuckDB Go client, duckdb-go, is a SQL driver that conforms to Go's built-in database/sql interface, so DuckDB is used through the same API as any other Go SQL database. On top of database/sql, the client adds DuckDB-specific interfaces for the Appender, Apache Arrow, user-defined functions, and profiling. This page focuses on installation. The other pages in this section cover connecting and each feature in detail.

For general instructions on the database/sql interface, see the official documentation and the Go database access tutorial.

Installation

The client is a Go module. Add it to a project with go get, using the /v2 major-version suffix:

go get github.com/duckdb/duckdb-go/v2

To copy the module's dependencies into the project's vendor directory, including the pre-built DuckDB libraries from duckdb-go-bindings, run go mod vendor.

DuckDB is written in C++, so the client uses cgo and requires a C compiler to build. By default it statically links a pre-built DuckDB library into the binary, so no separate DuckDB installation is needed. Pre-built libraries ship for macOS (amd64, arm64), Linux (amd64, arm64), and Windows (amd64). Other platforms, custom builds, and dynamic linking are covered in Troubleshoot.

Importing

To register the driver, import the package for its side effects with the blank identifier alongside database/sql:

import (
    "database/sql"

    _ "github.com/duckdb/duckdb-go/v2"
)

The import registers a driver named duckdb with database/sql. Code that calls the client's own types and functions directly, such as the Appender or user-defined functions, imports the package under its duckdb name instead of with the blank identifier:

import "github.com/duckdb/duckdb-go/v2"

Versioning

Starting with DuckDB v1.5.0, the duckdb-go version encodes the DuckDB version it bundles in its second semantic-versioning component. That component is the DuckDB major, minor, and patch numbers concatenated, with minor and patch each zero-padded to two digits: DuckDB v1.5.0 maps to duckdb-go v2.10500.x, and DuckDB 1.5.5 maps to v2.10505.0. The README has the full mapping table for earlier releases.

The LTS release line that stays on DuckDB 1.4 Andium is published as its own tags, which still follow the client's older versioning scheme. Select one in go.mod the same way as any other version; see the releases page for the available tags.

This project moved from github.com/marcboeker/go-duckdb to github.com/duckdb/duckdb-go starting with v2.5.0. All versions prior to v2.5.0 use the old import paths. See Migrating from marcboeker/go-duckdb below.

Basic API Usage

Open a database with sql.Open(), passing the driver name duckdb and a data source name (DSN). An empty DSN, or the DSN :memory:, opens an in-memory database, and a file path opens (or creates) a persistent database. From there, Exec, Query, and QueryRow run statements exactly as they do for any database/sql driver:

package main

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

    _ "github.com/duckdb/duckdb-go/v2"
)

func main() {
    db, err := sql.Open("duckdb", "")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    _, err = db.Exec(`CREATE TABLE people (id INTEGER, name VARCHAR)`)
    if err != nil {
        log.Fatal(err)
    }
    _, err = db.Exec(`INSERT INTO people VALUES (42, 'John')`)
    if err != nil {
        log.Fatal(err)
    }

    var (
        id   int
        name string
    )
    row := db.QueryRow(`SELECT id, name FROM people`)
    err = row.Scan(&id, &name)
    if errors.Is(err, sql.ErrNoRows) {
        log.Println("no rows")
    } else if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("id: %d, name: %s\n", id, name)
}

This example follows the client's simple example. Run Queries covers sending queries, binding parameters, and reading results in full.

Data Source Names

The DSN passed to sql.Open() is the database path followed by optional DuckDB configuration options as URL-style query parameters:

// In-memory database: an empty DSN and ":memory:" are equivalent.
db, err := sql.Open("duckdb", "")

// Persistent database, created if it does not exist.
db, err := sql.Open("duckdb", "/path/to/foo.db")

// Persistent database with configuration options.
db, err := sql.Open("duckdb", "/path/to/foo.db?access_mode=read_only&threads=4")

To run initialization steps, such as SET statements, before the first query, open the database with sql.OpenDB() and a Connector. See Connect for connectors, configuration, and the connection lifetime.

Build Tags

Some client features are gated behind Go build tags, passed to go build with the -tags flag, for example go build -tags=duckdb_arrow. The available tags:

Build tag Enables
duckdb_arrow The Apache Arrow interface. It is a heavy dependency, so it is opt-in.
duckdb_use_lib Dynamically link against a DuckDB library on the system instead of statically linking the bundled one. See Troubleshoot.
duckdb_use_static_lib Statically link against a custom DuckDB static library instead of the bundled one. See Troubleshoot.

Bundled Extensions

Every pre-built library statically links DuckDB's default extensions: ICU, JSON, Parquet, and Autocomplete. Automatic extension loading is also enabled, so other core extensions install and load on first use.

Migrating from marcboeker/go-duckdb

The project moved from github.com/marcboeker/go-duckdb to github.com/duckdb/duckdb-go with v2.5.0. To migrate a project, update the dependency and rewrite the import paths with gofmt:

# Update the dependency.
go get github.com/duckdb/duckdb-go/[email protected]

# Rewrite the import paths.
gofmt -w -r '"github.com/marcboeker/go-duckdb/v2" -> "github.com/duckdb/duckdb-go/v2"' .

# If the mapping or arrowmapping submodules are used, also run:
gofmt -w -r '"github.com/marcboeker/go-duckdb/mapping" -> "github.com/duckdb/duckdb-go/v2/mapping"' .
gofmt -w -r '"github.com/marcboeker/go-duckdb/arrowmapping" -> "github.com/duckdb/duckdb-go/v2/arrowmapping"' .

# Clean up.
go mod tidy

Moving to v2 also introduced a few breaking changes, including opt-in Arrow support and stricter JSON scanning. See Troubleshoot and the README for the complete list.

Further Reading

  • Connect — opening in-memory and file-backed databases, DSN configuration, connectors, and the connection lifetime.
  • Run QueriesExec, Query, prepared statements, parameter binding, transactions, and scanning results into Go values.
  • Import Data — bulk loading with the Appender and reading directly from Parquet, CSV, and JSON files.
  • Handle Results — the Apache Arrow interface for columnar result exchange.
  • Write User Defined Functions — scalar and table user-defined functions, and replacement scans.
  • Profile and Monitor — query profiling and logging.
  • Troubleshoot — linking, cgo, Windows setup, and other build and runtime issues.
  • Clients Overview — the other client APIs DuckDB provides alongside Go.

Acknowledgements

We would like to thank Marc Boeker for the initial implementation of the DuckDB Go client and for his continued work on it as part of this joint effort with the DuckDB team.

Pages in This Section

© 2026 DuckDB Foundation, Amsterdam NL
DuckDB Home Code of Conduct Trademark Use Blog