pg-java is a modern, PostgreSQL-specific database driver for the JVM.
- PostgreSQL-first. The initial API is designed around PostgreSQL's wire protocol and feature set rather than the lowest-common-denominator constraints of JDBC. This lets us expose PostgreSQL's capabilities directly and idiomatically.
- Eventually JDBC compliant. A JDBC-compliant layer is a long-term goal, but it will be built on top of the native API rather than dictating its shape. We do not want to be bound by the historical warts of JDBC from day one.
- Modern Java. Written in plain Java targeting Java 21+. The driver is virtual-thread friendly: it uses simple, blocking-style code that does not pin carrier threads, so applications can run it on virtual threads without an async framework.
- Streaming, pull-first. The core query primitive is a pull cursor that
reads one row at a time and never buffers the whole result set; list/
forEach/ map helpers are built on top. - Full featured. Over time the driver aims to support the breadth of
PostgreSQL functionality (extended query protocol, COPY, LISTEN/NOTIFY, binary
formats, SSL/TLS, SCRAM authentication with channel binding, and more). It does
not ship its own connection pool; instead it provides the lifecycle primitives
that external pools (and the JDBC
DataSource) need.
Under active development; pre-release and not yet published to Maven Central.
The core driver is functional: it connects over plain TCP and TLS, authenticates
(including SCRAM-SHA-256 with channel binding), and runs the simple and extended
query protocols. A JDBC layer (java.sql.*, registered via java.sql.Driver) is
implemented on top of it. The test suite includes integration tests that run
against real PostgreSQL (and PgBouncer) via Testcontainers. APIs are still
evolving and there are no compatibility guarantees yet. The implementation
roadmap (phased, commit-by-commit) lives in
docs/plans/overall.md, which also defines the
"first useful JDBC release" minimum.
The JDBC layer registers itself for the jdbc:pg: scheme (ADR-0015), and takes
libpq-style parameters:
String url = "jdbc:pg://localhost:5432/appdb?user=app&sslmode=verify-full";
try (Connection connection = DriverManager.getConnection(url, "app", secret);
PreparedStatement statement = connection.prepareStatement("select id from t where name = ?")) {
statement.setString(1, "widget");
try (ResultSet rows = statement.executeQuery()) {
while (rows.next()) {
System.out.println(rows.getLong(1));
}
}
}It also answers to jdbc:postgresql: for ported applications, though which
driver claims that scheme when real pgjdbc is also on the path is a decision of
its own (ADR-0015). The PostgreSQL-native API underneath it is
org.postgresql.client.core.PgConnections.connect(...), which returns a
PgConnection and never mentions java.sql.
pg-java is a multi-module Maven project. A parent (aggregator) POM ties the
modules together. The modules are:
postgresql-client-protocol- Low-level PostgreSQL wire protocol: serializing and deserializing frontend/backend messages and data types. No connection or I/O policy lives here, just the on-the-wire encoding. Has no dependency on the other modules.postgresql-client- The core driver. Connection management, authentication, TLS, the simple and extended query protocols, and the idiomatic PostgreSQL-first public API. Depends onpostgresql-client-protocol.postgresql-client-jdbc- The JDBC layer (java.sql.*) implemented on top of the core driver. Depends onpostgresql-client. Registers ajava.sql.Driverand providesConnection,PreparedStatement,ResultSet,DatabaseMetaData,DataSource, and XA support.postgresql-client-pgjdbc-compat- A pgjdbc source-compatibility layer on top ofpostgresql-client-jdbc, exposingorg.postgresql.Driverand commonorg.postgresql.*types. It is a migration aid, not a certified drop-in (yet): the exception types (PSQLException/ServerErrorMessage), the pgjdbc-identical driver name, and the vendor-extension ring (PGConnection,PGobject, geometric types,PGInterval,CopyManager,LargeObjectManager,PGSimpleDataSource) are in place, but somePGConnectionmethods are still stubbed and several functional paths await live-server verification. Treat the "drop-in" goal conservatively until that ring fully lands (seedocs/follow-up.md, N4.3).postgresql-client-bench- A driver-agnostic, pgbench-style JDBC benchmark that measures the driver, not the database. The driver under test (pg-java or pgjdbc) is supplied at runtime, never bundled. Build-only; not published. Seepostgresql-client-bench/README.md.postgresql-client-bench-jmh- Server-free JMH micro-benchmarks for the codec, framing and buffer paths, where allocation (bytes/op) is the tracked number. Seedocs/benchmarks/for the reference runs. Build-only; not published.postgresql-client-coverage- Aggregates per-module JaCoCo coverage into one combined report. Build-only; not published.postgresql-client-native-smoke- A GraalVM native-image smoke gate: it compiles the native-image metadata shipped bypostgresql-client-jdbcandpostgresql-client-pgjdbc-compatinto a native binary and runs it, catching metadata regressions. Off by default (a plain build only compiles the probe); the native build runs under thenative-smokeprofile on a GraalVM JDK. Build-only; not published.
- Build/runtime: Java 21 or newer.
- Build tool: Apache Maven. A Maven Wrapper
(
./mvnw) is checked in, so a separately installed Maven is optional; the wrapper downloads the pinned version on first use.
./mvnw clean install(or mvn clean install with a locally installed Maven).
Unit tests run with plain Maven and need no Docker:
mvn testIntegration tests (Testcontainers against a real PostgreSQL, and PgBouncer where
relevant) are gated behind the integration-tests profile so the default build
stays Docker-free. They require a running Docker daemon:
mvn verify -Pintegration-testsBy default the integration tests run against postgres:17; pass
-Dpg.it.image=<image> to test another server image, or use
scripts/run-integration-matrix.sh to sweep several PostgreSQL versions.
To run the shared-server integration tests against an already-running
PostgreSQL instead of Docker, set -Dpg.it.host:
mvn verify -Pintegration-tests -Dpg.it.host=localhostThe remaining coordinates default to port 5432 and postgres for the user,
password, and database; override them with -Dpg.it.port, -Dpg.it.user,
-Dpg.it.password, and -Dpg.it.database. The special-purpose harnesses
(TLS, PgBouncer, auth, unix socket) provision their own containers and are
skipped entirely when pg.it.host is set, so an external-server run never
touches Docker.
See AGENTS.md for project conventions, architecture notes, and guidance for both human and AI contributors.
Please do not report vulnerabilities in a public issue. See SECURITY.md for the private disclosure process, and for the security-relevant defaults that are documented decisions rather than open findings.
pg-java is released under the PostgreSQL License,
the same permissive license used by PostgreSQL itself.
The postgresql-client-pgjdbc-compat module deliberately mirrors the public
org.postgresql.* API of pgjdbc, which is
distributed under the BSD 2-Clause License and, like this project, is copyright
the PostgreSQL Global Development Group. See that module's README.md.