minato

港 - harbour. Where connections dock and wait to be dispatched.

An independent PostgreSQL client for Erlang.

Status

Early, and usable end to end: codecs, protocol, authentication with channel binding, TLS, connections, queries, transactions, a pool, LISTEN/NOTIFY, telemetry and logs. Nothing runs on it in production yet, and the API is not stable. Read the design guide before depending on it.

Install

{deps, [{minato, "~> 0.1"}]}.
{ok, _Pid} = minato:start_pool(main, #{
size => 10,
connection => #{host => "localhost", user => ~"minato",
password => ~"minato", database => ~"minato_test"}
}),
{ok, #{rows := [{42}]}} = minato:query(main, ~"SELECT $1::int4", [42]),
{ok, done} = minato:transaction(main, fun(Conn) ->
{ok, _Result, Written} = minato_query:query(Conn, ~"INSERT INTO t VALUES ($1)", [1]),
{ok, done, Written}
end).

Getting started is the ten minute version.

What is different about it

Guides

Testing

rebar3 eunit needs nothing installed: unit tests and PropEr round trips for every type in both wire formats, byte for byte tests of every protocol message against the documented format, framing properties that cut a stream at every byte and require it back whole, and SCRAM tampering properties stated over every byte position rather than as a few examples. The protocol round trips do not compare an encoder against itself: frontend messages are read back by a separate reader written from the same documentation, and backend messages are built by a separate writer.

rebar3 ct needs a PostgreSQL:

docker compose -f test/docker-compose.yml up -d
rebar3 ct
docker compose -f test/docker-compose.yml down -v

CI runs all of it on OTP 28 and 29.

Requirements

Build and test on OTP 28 or later. OTP 29 is the intended floor for released versions; the minimum_otp_vsn gate reads 28 because the pre-push checklist runs elp lint and elp eqwalize-all and ELP publishes no OTP 29 binary.

Prior art

minato is an independent implementation. It contains no code from any other project and is not a fork of one. Wire formats are taken from the PostgreSQL documentation and the documented binary send and receive representations, not from any existing client.

These projects were studied as architecture and are acknowledged as influences: pgo, epgsql, Postgrex, asyncpg and pgx.

pg_types and pgo are test profile dependencies only: pg_types as a differential oracle, pgo as a transport that carries minato's bytes to a real server. Neither is shipped at run time and neither is read as a source of implementation.

Licence

Apache-2.0. Copyright 2026 Widgrens IT AB (org.nr 559241-2752). See LICENSE.