Skip to Content
We are live but in Staging 🎉

Connect

This page is the Postgres wire only. S3, Bolt, Qdrant, Pinecone, GraphQL and gRPC endpoints are on Connect & wire adapters.

Connection string

dodil data connect <bucket> -o psql # prints the URL below with your key filled in dodil data connect <bucket> -o env # export DATA_PG_URL=…
postgresql://<user>:<password>@pg.uk-lon-1.dodil.io:5432/<bucket>?sslmode=require

Send the bare bucket name as the database. The gateway maps it to your organisation’s storage; never prefix it yourself. Postgres schemas do not exist: the bucket is the only namespace, a leading public. qualifier is stripped, and CREATE SCHEMA public / SET search_path are accepted with no effect.

The server identifies itself as PostgreSQL 16.0 (Dodil Tables adapterd), so drivers that gate features on the server version take the Postgres 16 path.

TLS

The door listens on a raw host port and terminates TLS with public Let’s Encrypt certificates.

ClientRecommendedWhy
Go (pgx), Node (node-postgres), JVM (pgJDBC)sslmode=verify-fullThey use the runtime’s system trust store — zero setup
libpq family (psql, psycopg, SQLAlchemy)sslmode=verify-full sslrootcert=systemlibpq only reads ~/.postgresql/root.crt unless told otherwise; sslrootcert=system needs libpq 16+ (older: point at the OS bundle, e.g. /etc/ssl/cert.pem)
Anything, minimumsslmode=requireEncrypts but does not authenticate the server

Never use prefer: it falls back to plaintext silently, and on this wire your password is your credential. Do not pin the certificate; it rotates about every 60 days.

Credentials

Credentialuserpassword
API key (issued on the bucket’s API Keys page)the dk_… key idthe key secret (shown once at issue time)
Service account (CI, headless)client_idclient_secret
Bearer JWT (dodil auth login)any stringthe JWT

Dispatch is by shape: a JWT-shaped password is a token, a dk_ id is an API key, anything else is treated as a service account. A rejected credential is FATAL 28P01. One credential works on every wire; see Auth & Access.

Sessions, pooling and timeouts

A session holds an open transaction, prepared statements, cursors and a few settings — nothing else. That makes the wire friendly to connection poolers (PgBouncer in session or transaction mode, an ORM’s built-in pool):

  • Prepared statements work ($1…$n, typed from the OIDs the driver declares; col = ANY($1) with an array bind is the filter-by-list idiom).
  • Transactions are real: BEGIN / COMMIT / ROLLBACK, SAVEPOINT, RELEASE, ROLLBACK TO. See Transactions & concurrency.
  • COPY <table> [(cols)] FROM STDIN [WITH (FORMAT text|csv)] streams bulk rows; COPY TO is refused.
  • Server-side cursors — DECLARE … CURSOR FOR, FETCH, CLOSE; forward-only.
  • statement_timeout is honoured: SET statement_timeout = 5000 or TO '5s'; expiry is 57014, pg’s own shape.
  • LISTEN / UNLISTEN are accepted with no effect — there is no notification channel. Other SET parameters (TimeZone, search_path, isolation level) are accepted with no effect too; TimeZone raises a notice because timestamps are always UTC.

SHOW answers the fixed set drivers probe at connect: server_version, client_encoding (UTF8), standard_conforming_strings (on), DateStyle (ISO, MDY), TimeZone (UTC), integer_datetimes (on), search_path, statement_timeout.

Drivers and ORMs

The ORM conformance suite runs real frameworks in four languages against the wire on every release.

Driver / ORMStatusNotes
psycopg 3Verifiedtext and binary parameters, COPY, server cursors
SQLAlchemy 2 (psycopg 3)Verifiedcreate_all, Core and ORM Session, optimistic versioning, RETURNING
Django ORMVerifiedconnect-time set_config('TimeZone', …) answered; migrations run
AlembicVerifiedupgrade/downgrade; a dropped never-stored constraint name is a no-op
GORM (pgx driver)VerifiedAutoMigrate, CRUD, RETURNING
SQLx (Rust)Verifiedcompile-time checked queries, native JSONB decode
node-postgres (pg)Verifiedparameterised queries, arrays
PrismaVerifieddb push, migrate, model CRUD; introspection answers the describer battery
pgx direct (Go), pgJDBC, asyncpg, NpgsqlExpectedstandard protocol paths; not exercised by the suite

Three things every ORM should know: FOREIGN KEY is enforced on insert (23503) but not on the parent’s delete, and the catalog does not report FK constraints back, so a migration diff sees them missing; ON DELETE CASCADE and DEFERRABLE options are refused at DDL (see Constraints); and a column declared INTEGER is stored as 64-bit and introspects as BIGINT (see Data types). The framework-by-framework checklist is on Migrating from Postgres.

From the CLI

dodil data pg -b <bucket> "SELECT count(*) FROM orders" # this SQL over the Postgres wire dodil data sql -b <bucket> "SELECT count(*) FROM orders" # the same SQL over the gRPC door

Omit the SQL to open a REPL. See CLI.