The C++ connector for PostgreSQL
libpqxx is a C++ client API for PostgreSQL, the
enterprise-strength open-source relational database. (If "PostgreSQL" is too
verbose, call it by its shorter name, postgres).
If you are writing software in C++ that needs to access databases managed by postgres —on just about any platform— then libpqxx is the library you use.
The source code for libpqxx is available under the BSD license, so you're free to download it, pass it on to others, change it, sell it, include it in your own code, and share your changes with anyone you choose. No charge, no catch. Also, no guarantees. :-)
Libpqxx is a wrapper around the C client API, called libpq. But for bulk data retrieval it can actually be faster than libpq. It also provides an easier, more "C++-native" API with advanced language features.
Finding Everything
Quick links:
-
Documentation is at ReadTheDocs.
-
Code, bug tracker, and releases are on Github.
-
Download source archives for released versions also on github.
-
Stats and insights are in OpenHub
News
2026-02-28: libpqxx 8.0 released
This is the big one, folks. Years in the making, this release raises the minimum C++ version to C++20 and the minimimum libpq & PostgreSQL versions to 13. (It won't stop you from working with 11 or 12, but there's no guarantees that it'll work. Anything older than 11 and it'll just refuse.)
Find it, with all the major changes, on GitHub. Warning: there's a lot!
For the git repo, issues, and discussions, see the main GitHub project.
Enjoy!
If you wish to contribute but don't know how, please consider sponsoring us through GitHub or through Buy Me A Coffee.
Technical Overview
This library works on top of the C-level API library, libpq. That one comes
with postgres. You will link your program with both libpqxx and libpq, in
that order.
(In some cases, libpqxx can actually be faster than libpq. In most cases there is likely to be a very slight performance overhead, combined with a lot of convenience, simplicity, and "C++-native accent." See this presentation on YouTube, May 2024 for an overview.)
Coding with libpqxx revolves around transactions. Transactions are a central concept in database management systems, but they are widely under-appreciated among application developers. In libpqxx, they're fundamental.
With conventional database APIs, you issue commands and queries to a database session or connection, and optionally create the occasional transaction. In libpqxx you start with a connection, but you do all your SQL work in transactions that you open in your connection. You commit each transaction when it's complete. If you don't, all changes made inside the transaction get rolled back.
There are several types of transactions with various "quality of service" properties. If you really don't want a transaction on the database, one of the available transaction types is called nontransaction. It provides basic non-transactional behaviour. (This is sometimes called "autocommit": it commits every successful command right away).
You can execute queries in different ways, each by calling methods on the
transaction:
* "query" methods execute a query, wait for the full result data to come back,
and provide you with each row of data converted to field types of your choice.
* "stream" methods execute a query, taking a bit more time to start up, but
the data then comes in at a higher rate, and you can start processing each row
right as it comes in. Just like the "query" methods, they convert the data to
field types of your choice.
* "exec" methods execute a query, wait for the full result to come in, and then
give you a result object. It's a container of rows (and each row is a
container of fields), but it also contains some metadata about the result set.
Either way, don't do any if statements to check for errors when you execute an
SQL command. If something goes wrong, the function will throw an exception.
Quick example
Can't have a database example without an Employee table. Here's a simple application: find an employee by name, and raise their salary by 1 whatever-it-is-they-get-paid-in.
This example is so simple that anything that goes wrong crashes the program. You won't need to do a lot more to fix that, but we'll get to it later.
#include <iostream>
#include <pqxx/pqxx>
int main(int, char *argv[])
{
// (Normally you'd check for valid command-line arguments.)
char const *const name = argv[1];
pqxx::connection cx{"postgresql://accounting@localhost/company"};
pqxx::work tx{cx};
// For querying just one single value, the transaction has a shorthand method
// query_value().
//
// The employee ID shows up in the query as "$1"; that means we'll pass it as
// a parameter. Pass all parameters together in a single "params" object.
int employee_id = tx.query_value<int>(
"SELECT id "
"FROM Employee "
"WHERE name = $1", pqxx::params{name});
std::cout << "Updating employee #" << employee_id << '\n';
// Update the employee's salary. Use exec() to perform the command, and
// no_rows() to check that it produces no result rows. If the result does
// contain data, this will throw an exception.
tx.exec(
"UPDATE Employee "
"SET salary = salary + 1 "
"WHERE id = $1",
pqxx::params{employee_id}
).no_rows();
// Make our change definite.
tx.commit();
}
You'll find more detailed explanations and reference-style docs on the ReadTheDocs site.
Building your libpqxx program
The details depend on your system and compiler. On a typical Unix-like system, you might do:
c++ add_employee.cxx -lpqxx -lpq
Remember to keep the -lpqxx and -lpq in that order! Otherwise the linker
will complain bitterly about missing functions like PQconnectdb and PQexec.
If libpqxx is installed in a nonstandard location, such as /usr/local, you
may need to add options like -I/usr/local/include (to make the compiler find
headers pqxx/* in /usr/local/include/pqxx), and/or -L/usr/local/lib (to
make the linker find the library in /usr/local/lib).
This should work on most GNU/Linux systems (Mint, Debian, Fedora, Gentoo,
Red Hat, Slax, Ubuntu, etc.), BSD systems (FreeBSD, NetBSD, OpenBSD), vaguely
Unix-like systems such as Apple's macOS, and so on — as long as you have
libpqxx, libpq, and a C++ compiler installed. If your C++ compiler has a
different name on the command line, use that instead of "c++".
It works differently on Microsoft Windows, though there are development environments out there that behave more like a Unix system.
Handling errors
Errors are exceptions, and derived from std::exception, just like you'd
expect. So you can handle database errors like all others:
#include <iostream>
#include "my-db-code.hxx"
int main()
{
try
{
do_db_work(trans);
}
catch (std::exception const &e)
{
std::cerr << e.what() << std::endl;
return 1;
}
}
Of course libpqxx also defines its own exception hierarchy for errors it throws, so you can handle those specially if you like:
#include <iostream>
#include <pqxx/except>
#include "my-db-code.hxx"
int main(int argc, char **)
{
try
{
do_db_work(trans);
}
catch (pqxx::failure const &e)
{
// It's a libpqxx exception. Print detailed information.
std::cerr << "Database error: " << e.what() << '\n';
// If this is libpqxx 8.0 or better:
std::cerr << "Occurred at " << pqxx::source_loc(e.location()) << '\n';
if (!std::empty(e.query()))
std::cerr << "Query was: " << e.query() << '\n';
return 2;
}
catch (std::exception const &e)
{
// Some other exception. All we know is it has a what().
std::cerr << e.what() << std::endl;
return 1;
}
}
Just one caveat: not all platforms support throwing an exception in a shared library and catching it outside that shared library. Unless you're building for Windows, it's probably a good habit to use static libraries instead.
Complete example
Here's a more complete example, showing iteration and direct field access.
#include <iostream>
#include <pqxx/pqxx>
/// Query employees from database. Return result.
pqxx::result query()
{
pqxx::connection cx{"postgresql://accounting@localhost/company"};
pqxx::work tx{cx};
// Silly example: Add up all salaries. Normally you'd let the database do
// this for you.
long total = 0;
for (auto [salary] : tx.query<int>("SELECT salary FROM Employee"))
total += salary;
std::cout << "Total salary: " << total << '\n';
// Execute and process some data.
pqxx::result r{tx.exec("SELECT name, salary FROM Employee")};
for (auto row: r)
std::cout
// Address column by name. Use c_str() to get C-style string.
<< row["name"].c_str()
<< " makes "
// Address column by zero-based index. Use as<int>() to parse as int.
<< row[1].as<int>()
<< "."
<< std::endl;
// Not really needed, since we made no changes, but good habit to be
// explicit about when the transaction is done.
tx.commit();
// Connection object goes out of scope here. It closes automatically.
// But the result object remains valid.
return r;
}
/// Query employees from database, print results.
int main()
{
try
{
pqxx::result r{query()};
// Results can be accessed and iterated again. Even after the connection
// has been closed.
for (auto row: r)
{
std::cout << "Row: ";
// Iterate over fields in a row.
for (auto field: row) std::cout << field.c_str() << " ";
std::cout << std::endl;
}
}
catch (pqxx::failure const &e)
{
std::cerr << "SQL error: " << e.what() << '\n';
// If this is libpqxx 8.0 or better:
std::cerr << "Occurred at " << pqxx::source_loc(e.location()) << '\n';
if (!std::empty(e.query()))
std::cerr << "Query was: " << e.query() << '\n';
return 2;
}
catch (std::exception const &e)
{
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
}
Results and result rows have all the member functions you expect to find in a
container: begin()/end(), front()/back(), size(), index operator, and
so on. The contents are immutable.
Donate
If you'd like to reward me for the work on libpqxx, you can now do that on buymeacoffee.com. It will help me pay for the costs of developing this library. And wouldn't it be great to have some swag for those help improve the code, or answer questions other users have?
