Skip to main content
Preslav Rachev

If you are betting on PostgreSQL, pgx is the right choice.

Here is a question I was asked by my students recently:

When using PostgreSQL, which driver should we go for?

As we all know, Go does not provide drivers as part of its standard library, and rightfully so. This would have been an overkill to maintain for all the different database vendors and versions. Instead, the job has been left to the community.

If we check the list for PostgreSQL drivers, we will see two main contenders:

pgx is younger, but catches people’s attention much faster

pq #

pq implements the standard sql.DB specification, and as such, may be the first choice that most people new to the language go for. If you are looking for a driver, which simply gives you access to a standard relational database, pq is just fine. All you need to do is import it, and you are good to go:

import (
	_ "" // Don't forget the driver!

dbPath := "postgres://path_to_the_db"
db, err := sql.Open("postgres", dbPath)

Unfortunately, pq has not been in active feature development as of a couple of years. It is still under active maintenance, so anything critical will still make it into the repo, but it may eventually diverge from the development of future PostgreSQL versions:

This package is effectively in maintenance mode and is not actively developed. Small patches and features are only rarely reviewed and merged. We recommend using pgx which is actively maintained.

pgx #

That said, I would advise people to seriously look at pgx as an alternative implementation:

pgx aims to be low-level, fast, and performant, while also enabling PostgreSQL-specific features that the standard database/sql package does not allow for. The driver component of pgx can be used alongside the standard database/sql package.

Let’s try to decode the above message. Because pgx offers a compatibility layer with database/sql , it can be used in exactly the same way as we used pq before. If you are in a hurry, and don’t have time to explore all the cool features of pgx, you can simply do the following, and go on with your life:

import (
	_ ""

But pgx can do a lot more #

While it is perfectly fine to use pgx as a standard database driver replacement of pq, it can do a whole lot more when used on its own. See, pgx wasn’t developed to comply with the standard library’s design specification. While it mimics the functions, methods, and types from the database/sql package, under the hood, it provides a completely different implementation that directly uses the best out of PostgreSQL, because it was designed for it.

// source:

dbpool, err := pgxpool.Connect(context.Background(), os.Getenv("DATABASE_URL"))
// handle the error
defer dbpool.Close()

err = dbpool.QueryRow(context.Background(), "select 'Hello, world!'").Scan(&greeting)
// pgx mimics the standard library for the most part

pgx was designed for performance right out of the gate, and the fact that it forces the developer to think about connection pools right from the start pays off later on.

In addition, when not tied to the standard library, pgx can make use of a faster binary protocol for marshalling and unmarshalling of JSON data from Postgres. It also understands and supports most of the data types specific to Postgres.

The verdict #

If your code makes use of pq already, or if you are not sure, whether you will keep using PostgreSQL in the near future, it is OK to keep it as it is. My advice is to try and give pgx’s compatibility layer a try. It won’t give you any performance advantage over pq, but it will move you a step further in the direction, without requiring any changes to the rest of your code. Once you have settled in on using pgx, you might as well replace the compatibility layer with a direct pgx pool. This may require a few more changes, but for the most part, your code should be easy to adjust.

Accessing PostgreSQL databases in Go
This post discusses some options for accessing PostgreSQL databases from Go. I'll only be covering low-level packages that provide access to the underlying database; this post is not about ORMs, which were covered earlier in this blog. The full source code accompanying this post is on GitHub.
Go - lib/pq or pgx - which performs better?
Devandchill is a coding and tech blog oriented to go, .net and databases made by Pablo Morelli
How We Went All In on sqlc/pgx for Postgres + Go
Touring the ORM and Postgres landscape in Go, and why sqlc is today’s top pick.
How to work with Postgres in Go
Using Postgres from Golang in a not-exactly-correct fashion can lead to data corruption and downtime.

Have something to say? Join the discussion below 👇

Want to explore instead? Fly with the time capsule 🛸

You may also find these interesting

Consistent > Idiomatic

·2 mins

As a software engineer, I’ve learned that consistency in code is crucial for the long-term success of a project, even when it means deviating from idiomatic principles.