How to Connect to MongoDB from Go

6 min readMongoDB

For MongoDB and Go there is one driver worth using: the official go.mongodb.org/mongo-driver, now on the v2 line. There is no real third-party alternative the way there is for SQL databases, so the interesting decisions are not which driver but how to use it correctly: creating a single client for the whole application, surviving the v2 API changes, and getting pooling and BSON mapping right. This guide covers all of that with working code.

The driver

PackageImport pathVersion (as of June 2026)
Official Go driver (v2)go.mongodb.org/mongo-driver/v2/mongov2.6.1

Install it with go get go.mongodb.org/mongo-driver/v2/mongo. The driver requires a recent Go toolchain (Go 1.25+ for the v2.6 line) and supports MongoDB 4.2 and higher.

If you are reading an older tutorial that imports go.mongodb.org/mongo-driver/mongo (no /v2), that is the v1 line. v2 is a separate module path, and the import change is the first thing to get right when following old material.

The v2 Connect change that breaks old code

The single biggest difference between v1 and v2 is the Connect signature. In v1 you called mongo.Connect(ctx, opts). In v2, Connect no longer takes a context:

client, err := mongo.Connect(options.Client().ApplyURI(uri))

The context moved onto the individual operations (client.Ping(ctx, ...), coll.Find(ctx, ...)), which is where it always belonged. If you copy v1 code into a v2 project, the compiler will complain about the extra argument. That is the expected signal, not a bug.

Connecting: one client, created once

mongo.Client is safe for concurrent use and manages its own connection pool internally. The cardinal rule is to create exactly one client when your application starts and reuse it everywhere. Creating a client per request defeats the pool and exhausts connections under load.

package main
 
import (
	"context"
	"log"
	"time"
 
	"go.mongodb.org/mongo-driver/v2/mongo"
	"go.mongodb.org/mongo-driver/v2/mongo/options"
)
 
func main() {
	uri := "mongodb://user:pass@localhost:27017/?authSource=admin"
 
	opts := options.Client().
		ApplyURI(uri).
		SetMaxPoolSize(50).
		SetServerSelectionTimeout(5 * time.Second)
 
	// v2: no context argument here.
	client, err := mongo.Connect(opts)
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		if err := client.Disconnect(context.Background()); err != nil {
			log.Print(err)
		}
	}()
 
	// Connect does not actually talk to the server. Ping forces it.
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := client.Ping(ctx, nil); err != nil {
		log.Fatal(err)
	}
 
	coll := client.Database("app").Collection("users")
	n, err := coll.CountDocuments(ctx, map[string]any{})
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("users: %d", n)
}

Connect is lazy; Ping is the real check

mongo.Connect returns a client immediately without verifying that any server is reachable. The driver connects lazily on the first operation. That means a wrong host, a firewall block, or bad credentials surface later, often inside a request handler. Call client.Ping at startup with a bounded context so connection problems fail loudly where you can handle them. Set SetServerSelectionTimeout so a dead server fails in seconds instead of the default 30.

Pooling

The driver maintains an internal pool per server. The setting that matters most is SetMaxPoolSize (default 100). The total connections your fleet opens is roughly maxPoolSize × number of app processes × number of mongod nodes the driver talks to. On a replica set or a shared cluster, multiply accordingly and keep the total under the server's connection limit. Lower the pool size if you run many application instances against one cluster. SetMinPoolSize keeps a warm floor of connections ready, which trims latency on the first requests after idle periods at the cost of holding connections open.

SRV connection strings and Atlas

MongoDB Atlas and many self-hosted setups hand you an mongodb+srv:// URI. The +srv scheme does two things automatically: it resolves the seed list via a DNS SRV record, and it implies tls=true. The Go driver handles SRV resolution natively, so no extra package is needed (unlike some other languages' drivers).

uri := "mongodb+srv://user:pass@cluster0.abcde.mongodb.net/?retryWrites=true&w=majority"
client, err := mongo.Connect(options.Client().ApplyURI(uri))

Two recurring gotchas:

  • Percent-encode credentials. If your username or password contains @, :, /, or other reserved characters, they must be URL-encoded in the URI or parsing fails or misreads the host.
  • Atlas IP allowlist. A correct URI that times out on server selection from a new environment is almost always the Atlas network access list, not your code. Add the client IP (or a VPC peering rule) before debugging the driver.

BSON and struct tags

MongoDB stores BSON, and the driver maps it to Go structs using bson struct tags. Without tags, the driver lowercases the Go field name, which is rarely what your documents use.

type User struct {
	ID    bson.ObjectID `bson:"_id,omitempty"`
	Name  string        `bson:"name"`
	Email string        `bson:"email"`
}

Note that in v2 the ObjectID type lives in the bson package (bson.ObjectID), another move from where v1 kept it (primitive.ObjectID). Use omitempty on _id so MongoDB generates the ObjectID on insert instead of writing a zero value.

Common errors

ErrorLikely cause
server selection error: context deadline exceededUnreachable host, firewall, or Atlas IP allowlist not updated
(AuthenticationFailed) ... auth errorWrong credentials, or missing/incorrect authSource (often admin)
error parsing uriUnencoded special characters in username/password
Connect undefined: too many argumentsPassing a context to v2 mongo.Connect (v1 habit)
client is disconnectedUsing a client after Disconnect, or sharing a closed client

The authSource case is the most common silent failure: credentials created in the admin database fail to authenticate against another database unless you tell the driver where the user lives, via ?authSource=admin in the URI.

Querying without writing connection code

If your goal is to explore a MongoDB database rather than build a service, a GUI client skips the driver setup. Mako connects to MongoDB with AI-assisted querying -- see our MongoDB GUI client guide for how it compares to Compass and Studio 3T. Connecting from another language? See How to Connect to MongoDB from Python and from Node.js.

Mako connects to MongoDB with AI-powered autocomplete. Try it free at mako.ai.

Mako — open source

Skip the terminal. Use Mako.

Connect your database, write queries with AI assistance, and import/export data in clicks. Free to start.