GoogleCloudPlatform/alloydb-go-connector

A Go library for connecting securely to your AlloyDB instances

70

stars

672

commits

Go

primary language

Sep 11, 2026

updated

alloydb
go
golang
libraries

README

alloydb-go-connector image

AlloyDB Go Connector

CI Go Reference

The AlloyDB Go Connector is the recommended way to connect to AlloyDB from Go applications. It provides:

  • Secure connections — TLS 1.3 encryption and identity verification, independent of the database protocol
  • IAM-based authorization — controls who can connect to your AlloyDB instances using Google Cloud IAM
  • No certificate management — no SSL certificates, firewall rules, or IP allowlisting required
  • IAM database authentication — optional support for automatic IAM DB authentication

Quick Start

Install the module:

go get cloud.google.com/go/alloydbconn

Connect using the standard database/sql package:

package main

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

    "cloud.google.com/go/alloydbconn/driver/postgres"
)

func main() {
    // Register the AlloyDB driver with the name "alloydb"
    // Uses Private IP by default. See Network Options below for details.
    cleanup, err := postgres.RegisterDriver("alloydb")
    if err != nil {
        log.Fatal(err)
    }
    defer cleanup()

    // Instance URI format:
    //   projects/PROJECT/locations/REGION/clusters/CLUSTER/instances/INSTANCE
    db, err := sql.Open("alloydb", fmt.Sprintf(
        "host=%s user=%s password=%s dbname=%s sslmode=disable",
        "projects/my-project/locations/us-central1/clusters/my-cluster/instances/my-instance",
        "my-user",
        "my-password",
        "my-db",
    ))
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    var greeting string
    if err := db.QueryRow("SELECT 'Hello, AlloyDB!'").Scan(&greeting); err != nil {
        log.Fatal(err)
    }
    fmt.Println(greeting)
}

The connector uses Application Default Credentials (ADC) automatically. For local development, run:

gcloud auth application-default login

Table of Contents

Prerequisites

IAM Permissions

The IAM principal (user or service account) making connections needs:

  • AlloyDB Client role (roles/alloydb.client)
  • Service Usage Consumer role (roles/serviceusage.serviceUsageConsumer)

Enable the AlloyDB API

Enable the AlloyDB API in your Google Cloud project.

Credentials

The connector uses Application Default Credentials (ADC)this is the recommended approach for most applications. ADC automatically finds credentials from the environment:

  • Local development: run gcloud auth application-default login once
  • Google Cloud (Compute Engine, Cloud Run, GKE, etc.): credentials are picked up automatically from the attached service account — no code changes needed
# One-time setup for local development
gcloud auth application-default login

If you need to supply credentials explicitly (e.g., in non-Google managed environments without Application Default Credentials), see the Configuring the Dialer section for less common alternatives.

Connecting with database/sql

The database/sql approach works with any library that accepts a *sql.DB.

import (
    "database/sql"
    "fmt"

    "cloud.google.com/go/alloydbconn"
    "cloud.google.com/go/alloydbconn/driver/postgres"
)

func connect(instURI, user, pass, dbname string) (*sql.DB, func() error, error) {
    // RegisterDriver registers the AlloyDB driver and returns a cleanup
    // function that stops background goroutines. Call cleanup when you are
    // done with the database connection to avoid a goroutine leak.
    cleanup, err := postgres.RegisterDriver("alloydb")
    if err != nil {
        return nil, nil, err
    }

    db, err := sql.Open("alloydb", fmt.Sprintf(
        // sslmode=disable is correct here: the connector handles TLS.
        "host=%s user=%s password=%s dbname=%s sslmode=disable",
        instURI, user, pass, dbname,
    ))
    if err != nil {
        return nil, cleanup, err
    }
    return db, cleanup, nil
}

Instance URI format: projects/PROJECT/locations/REGION/clusters/CLUSTER/instances/INSTANCE

Connecting with pgx

For direct control over connection pooling, use pgx with pgxpool:

import (
    "context"
    "fmt"
    "net"

    "cloud.google.com/go/alloydbconn"
    "github.com/jackc/pgx/v5/pgxpool"
)

func connect(ctx context.Context, instURI, user, pass, dbname string) (*pgxpool.Pool, func() error, error) {
    d, err := alloydbconn.NewDialer(ctx)
    if err != nil {
        return nil, func() error { return nil }, fmt.Errorf("failed to init dialer: %v", err)
    }
    // cleanup stops the dialer's background goroutines.
    cleanup := func() error { return d.Close() }

    config, err := pgxpool.ParseConfig(fmt.Sprintf(
        "user=%s password=%s dbname=%s sslmode=disable",
        user, pass, dbname,
    ))
    if err != nil {
        return nil, cleanup, fmt.Errorf("failed to parse config: %v", err)
    }

    // Tell pgx to use the AlloyDB connector for all connections.
    config.ConnConfig.DialFunc = func(ctx context.Context, _, _ string) (net.Conn, error) {
        return d.Dial(ctx, instURI)
    }

    pool, err := pgxpool.NewWithConfig(ctx, config)
    if err != nil {
        return nil, cleanup, fmt.Errorf("failed to connect: %v", err)
    }
    return pool, cleanup, nil
}

Network Options

AlloyDB supports three connectivity modes. The connector defaults to private IP.

Private IP (default)

Private IP requires your application to run within a VPC Network connected to your AlloyDB instance. No extra configuration is needed — the default d.Dial(ctx, instURI) call will connect over private IP.

Public IP

Pass WithPublicIP() to connect over the instance's public IP address.

With database/sql:

cleanup, err := postgres.RegisterDriver("alloydb",
    alloydbconn.WithDefaultDialOptions(alloydbconn.WithPublicIP()),
)

With pgx:

config.ConnConfig.DialFunc = func(ctx context.Context, _, _ string) (net.Conn, error) {
    return d.Dial(ctx, instURI, alloydbconn.WithPublicIP())
}

Private Service Connect (PSC)

Pass WithPSC() to connect via Private Service Connect.

With database/sql:

cleanup, err := postgres.RegisterDriver("alloydb",
    alloydbconn.WithDefaultDialOptions(alloydbconn.WithPSC()),
)

With pgx:

config.ConnConfig.DialFunc = func(ctx context.Context, _, _ string) (net.Conn, error) {
    return d.Dial(ctx, instURI, alloydbconn.WithPSC())
}

IAM Database Authentication

The connector supports Automatic IAM database authentication. With IAM auth, your application's IAM identity is used in place of a static database password.

Before you begin:

  1. Enable IAM authentication on your AlloyDB instance
  2. Add an IAM database user

Connect with IAM authentication:

// Pass WithIAMAuthN() to enable automatic IAM authentication.
cleanup, err := postgres.RegisterDriver("alloydb", alloydbconn.WithIAMAuthN())

Set the user field in your DSN based on your IAM identity type:

Identity typeUsername format
IAM user accountFull email: user@example.com
Service accountEmail without .gserviceaccount.com: my-sa@my-project.iam
db, err := sql.Open("alloydb", fmt.Sprintf(
    // Omit the password field when using IAM authentication.
    "host=%s user=%s dbname=%s sslmode=disable",
    instURI,
    "my-sa@my-project.iam",
    dbname,
))

Configuring the Dialer

Both postgres.RegisterDriver and alloydbconn.NewDialer accept options to customize connector behavior.

Explicit credentials (uncommon)

Most applications should rely on Application Default Credentials and won't need these options. Use them only when ADC isn't available in your environment.

From a service account key file:

cleanup, err := postgres.RegisterDriver("alloydb",
    alloydbconn.WithCredentialsFile("path/to/service-account-key.json"),
)

From a credentials JSON blob:

cleanup, err := postgres.RegisterDriver("alloydb",
    alloydbconn.WithCredentialsJSON([]byte(`{...}`)),
)

Set default dial options

Apply options to every connection made by the dialer:

d, err := alloydbconn.NewDialer(ctx,
    alloydbconn.WithDefaultDialOptions(
        alloydbconn.WithPublicIP(),
    ),
)

For all available options, see the alloydbconn.Option reference.

Observability

The connector exports metrics and traces via OpenCensus. Configure an exporter to send telemetry to your monitoring backend.

Metrics

MetricDescription
alloydbconn/dial_latencyDistribution of dialer latencies (ms)
alloydbconn/open_connectionsCurrent number of open AlloyDB connections
alloydbconn/dial_failure_countNumber of failed dial attempts
alloydbconn/refresh_success_countNumber of successful certificate refresh operations
alloydbconn/refresh_failure_countNumber of failed refresh operations
alloydbconn/bytes_sentBytes sent to an AlloyDB instance
alloydbconn/bytes_receivedBytes received from an AlloyDB instance

Traces

  • cloud.google.com/go/alloydbconn.Dial — the full dial operation
  • cloud.google.com/go/alloydbconn/internal.InstanceInfo — instance metadata retrieval
  • cloud.google.com/go/alloydbconn/internal.Connect — connection attempt using the ephemeral certificate
  • AlloyDB API client operations

Example: Cloud Monitoring and Cloud Trace

import (
    "contrib.go.opencensus.io/exporter/stackdriver"
    "go.opencensus.io/trace"
)

func main() {
    sd, err := stackdriver.NewExporter(stackdriver.Options{
        ProjectID: "my-project",
    })
    if err != nil {
        log.Fatal(err)
    }
    defer sd.Flush()

    trace.RegisterExporter(sd)
    sd.StartMetricsExporter()
    defer sd.StopMetricsExporter()

    // Use alloydbconn as usual.
}

Debug Logging

Enable debug logging to diagnose issues with the background certificate refresh. Implement the debug.ContextLogger interface and pass it to the dialer:

import (
    "context"
    "log"

    "cloud.google.com/go/alloydbconn"
)

type myLogger struct{}

func (l *myLogger) Debugf(ctx context.Context, format string, args ...interface{}) {
    log.Printf("[DEBUG] "+format, args...)
}

func connect(ctx context.Context) {
    d, err := alloydbconn.NewDialer(ctx,
        alloydbconn.WithContextDebugLogger(&myLogger{}),
    )
    // use d as usual...
}

Support Policy

This project follows semantic versioning. We release a new version monthly with features, bug fixes, and security updates. If no new features are added, we still release a PATCH version with updated dependencies. We recommend always using the latest version.

Supported Go Versions

We follow the Go Version Support Policy used by Google Cloud Libraries for Go.

Contributors

renovate-bot

354 commits

enocom

163 commits

jackwotherspoon

41 commits

GoogleCloudPlatform/alloydb-go-connector

A Go library for connecting securely to your AlloyDB instances

70

stars

672

commits

Go

primary language

Sep 11, 2026

updated

alloydb
go
golang
libraries

README

alloydb-go-connector image

AlloyDB Go Connector

CI Go Reference

The AlloyDB Go Connector is the recommended way to connect to AlloyDB from Go applications. It provides:

  • Secure connections — TLS 1.3 encryption and identity verification, independent of the database protocol
  • IAM-based authorization — controls who can connect to your AlloyDB instances using Google Cloud IAM
  • No certificate management — no SSL certificates, firewall rules, or IP allowlisting required
  • IAM database authentication — optional support for automatic IAM DB authentication

Quick Start

Install the module:

go get cloud.google.com/go/alloydbconn

Connect using the standard database/sql package:

package main

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

    "cloud.google.com/go/alloydbconn/driver/postgres"
)

func main() {
    // Register the AlloyDB driver with the name "alloydb"
    // Uses Private IP by default. See Network Options below for details.
    cleanup, err := postgres.RegisterDriver("alloydb")
    if err != nil {
        log.Fatal(err)
    }
    defer cleanup()

    // Instance URI format:
    //   projects/PROJECT/locations/REGION/clusters/CLUSTER/instances/INSTANCE
    db, err := sql.Open("alloydb", fmt.Sprintf(
        "host=%s user=%s password=%s dbname=%s sslmode=disable",
        "projects/my-project/locations/us-central1/clusters/my-cluster/instances/my-instance",
        "my-user",
        "my-password",
        "my-db",
    ))
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    var greeting string
    if err := db.QueryRow("SELECT 'Hello, AlloyDB!'").Scan(&greeting); err != nil {
        log.Fatal(err)
    }
    fmt.Println(greeting)
}

The connector uses Application Default Credentials (ADC) automatically. For local development, run:

gcloud auth application-default login

Table of Contents

Prerequisites

IAM Permissions

The IAM principal (user or service account) making connections needs:

  • AlloyDB Client role (roles/alloydb.client)
  • Service Usage Consumer role (roles/serviceusage.serviceUsageConsumer)

Enable the AlloyDB API

Enable the AlloyDB API in your Google Cloud project.

Credentials

The connector uses Application Default Credentials (ADC)this is the recommended approach for most applications. ADC automatically finds credentials from the environment:

  • Local development: run gcloud auth application-default login once
  • Google Cloud (Compute Engine, Cloud Run, GKE, etc.): credentials are picked up automatically from the attached service account — no code changes needed
# One-time setup for local development
gcloud auth application-default login

If you need to supply credentials explicitly (e.g., in non-Google managed environments without Application Default Credentials), see the Configuring the Dialer section for less common alternatives.

Connecting with database/sql

The database/sql approach works with any library that accepts a *sql.DB.

import (
    "database/sql"
    "fmt"

    "cloud.google.com/go/alloydbconn"
    "cloud.google.com/go/alloydbconn/driver/postgres"
)

func connect(instURI, user, pass, dbname string) (*sql.DB, func() error, error) {
    // RegisterDriver registers the AlloyDB driver and returns a cleanup
    // function that stops background goroutines. Call cleanup when you are
    // done with the database connection to avoid a goroutine leak.
    cleanup, err := postgres.RegisterDriver("alloydb")
    if err != nil {
        return nil, nil, err
    }

    db, err := sql.Open("alloydb", fmt.Sprintf(
        // sslmode=disable is correct here: the connector handles TLS.
        "host=%s user=%s password=%s dbname=%s sslmode=disable",
        instURI, user, pass, dbname,
    ))
    if err != nil {
        return nil, cleanup, err
    }
    return db, cleanup, nil
}

Instance URI format: projects/PROJECT/locations/REGION/clusters/CLUSTER/instances/INSTANCE

Connecting with pgx

For direct control over connection pooling, use pgx with pgxpool:

import (
    "context"
    "fmt"
    "net"

    "cloud.google.com/go/alloydbconn"
    "github.com/jackc/pgx/v5/pgxpool"
)

func connect(ctx context.Context, instURI, user, pass, dbname string) (*pgxpool.Pool, func() error, error) {
    d, err := alloydbconn.NewDialer(ctx)
    if err != nil {
        return nil, func() error { return nil }, fmt.Errorf("failed to init dialer: %v", err)
    }
    // cleanup stops the dialer's background goroutines.
    cleanup := func() error { return d.Close() }

    config, err := pgxpool.ParseConfig(fmt.Sprintf(
        "user=%s password=%s dbname=%s sslmode=disable",
        user, pass, dbname,
    ))
    if err != nil {
        return nil, cleanup, fmt.Errorf("failed to parse config: %v", err)
    }

    // Tell pgx to use the AlloyDB connector for all connections.
    config.ConnConfig.DialFunc = func(ctx context.Context, _, _ string) (net.Conn, error) {
        return d.Dial(ctx, instURI)
    }

    pool, err := pgxpool.NewWithConfig(ctx, config)
    if err != nil {
        return nil, cleanup, fmt.Errorf("failed to connect: %v", err)
    }
    return pool, cleanup, nil
}

Network Options

AlloyDB supports three connectivity modes. The connector defaults to private IP.

Private IP (default)

Private IP requires your application to run within a VPC Network connected to your AlloyDB instance. No extra configuration is needed — the default d.Dial(ctx, instURI) call will connect over private IP.

Public IP

Pass WithPublicIP() to connect over the instance's public IP address.

With database/sql:

cleanup, err := postgres.RegisterDriver("alloydb",
    alloydbconn.WithDefaultDialOptions(alloydbconn.WithPublicIP()),
)

With pgx:

config.ConnConfig.DialFunc = func(ctx context.Context, _, _ string) (net.Conn, error) {
    return d.Dial(ctx, instURI, alloydbconn.WithPublicIP())
}

Private Service Connect (PSC)

Pass WithPSC() to connect via Private Service Connect.

With database/sql:

cleanup, err := postgres.RegisterDriver("alloydb",
    alloydbconn.WithDefaultDialOptions(alloydbconn.WithPSC()),
)

With pgx:

config.ConnConfig.DialFunc = func(ctx context.Context, _, _ string) (net.Conn, error) {
    return d.Dial(ctx, instURI, alloydbconn.WithPSC())
}

IAM Database Authentication

The connector supports Automatic IAM database authentication. With IAM auth, your application's IAM identity is used in place of a static database password.

Before you begin:

  1. Enable IAM authentication on your AlloyDB instance
  2. Add an IAM database user

Connect with IAM authentication:

// Pass WithIAMAuthN() to enable automatic IAM authentication.
cleanup, err := postgres.RegisterDriver("alloydb", alloydbconn.WithIAMAuthN())

Set the user field in your DSN based on your IAM identity type:

Identity typeUsername format
IAM user accountFull email: user@example.com
Service accountEmail without .gserviceaccount.com: my-sa@my-project.iam
db, err := sql.Open("alloydb", fmt.Sprintf(
    // Omit the password field when using IAM authentication.
    "host=%s user=%s dbname=%s sslmode=disable",
    instURI,
    "my-sa@my-project.iam",
    dbname,
))

Configuring the Dialer

Both postgres.RegisterDriver and alloydbconn.NewDialer accept options to customize connector behavior.

Explicit credentials (uncommon)

Most applications should rely on Application Default Credentials and won't need these options. Use them only when ADC isn't available in your environment.

From a service account key file:

cleanup, err := postgres.RegisterDriver("alloydb",
    alloydbconn.WithCredentialsFile("path/to/service-account-key.json"),
)

From a credentials JSON blob:

cleanup, err := postgres.RegisterDriver("alloydb",
    alloydbconn.WithCredentialsJSON([]byte(`{...}`)),
)

Set default dial options

Apply options to every connection made by the dialer:

d, err := alloydbconn.NewDialer(ctx,
    alloydbconn.WithDefaultDialOptions(
        alloydbconn.WithPublicIP(),
    ),
)

For all available options, see the alloydbconn.Option reference.

Observability

The connector exports metrics and traces via OpenCensus. Configure an exporter to send telemetry to your monitoring backend.

Metrics

MetricDescription
alloydbconn/dial_latencyDistribution of dialer latencies (ms)
alloydbconn/open_connectionsCurrent number of open AlloyDB connections
alloydbconn/dial_failure_countNumber of failed dial attempts
alloydbconn/refresh_success_countNumber of successful certificate refresh operations
alloydbconn/refresh_failure_countNumber of failed refresh operations
alloydbconn/bytes_sentBytes sent to an AlloyDB instance
alloydbconn/bytes_receivedBytes received from an AlloyDB instance

Traces

  • cloud.google.com/go/alloydbconn.Dial — the full dial operation
  • cloud.google.com/go/alloydbconn/internal.InstanceInfo — instance metadata retrieval
  • cloud.google.com/go/alloydbconn/internal.Connect — connection attempt using the ephemeral certificate
  • AlloyDB API client operations

Example: Cloud Monitoring and Cloud Trace

import (
    "contrib.go.opencensus.io/exporter/stackdriver"
    "go.opencensus.io/trace"
)

func main() {
    sd, err := stackdriver.NewExporter(stackdriver.Options{
        ProjectID: "my-project",
    })
    if err != nil {
        log.Fatal(err)
    }
    defer sd.Flush()

    trace.RegisterExporter(sd)
    sd.StartMetricsExporter()
    defer sd.StopMetricsExporter()

    // Use alloydbconn as usual.
}

Debug Logging

Enable debug logging to diagnose issues with the background certificate refresh. Implement the debug.ContextLogger interface and pass it to the dialer:

import (
    "context"
    "log"

    "cloud.google.com/go/alloydbconn"
)

type myLogger struct{}

func (l *myLogger) Debugf(ctx context.Context, format string, args ...interface{}) {
    log.Printf("[DEBUG] "+format, args...)
}

func connect(ctx context.Context) {
    d, err := alloydbconn.NewDialer(ctx,
        alloydbconn.WithContextDebugLogger(&myLogger{}),
    )
    // use d as usual...
}

Support Policy

This project follows semantic versioning. We release a new version monthly with features, bug fixes, and security updates. If no new features are added, we still release a PATCH version with updated dependencies. We recommend always using the latest version.

Supported Go Versions

We follow the Go Version Support Policy used by Google Cloud Libraries for Go.

Contributors

renovate-bot

354 commits

enocom

163 commits

jackwotherspoon

41 commits

Languages

Go

98.6%

Shell

1.4%