oven-sh/bun
SQL clients
src/sql/ implements native Postgres and MySQL clients exposed to JavaScript as Bun.sql. SQLite is implemented separately in src/bun.js/bindings/sqlite/ and exposed as bun:sqlite.
Files
src/sql/
├── postgres/ # Postgres protocol (~lots of files)
├── postgres.zig # entry struct
├── mysql/ # MySQL protocol
├── mysql.zig # entry struct
└── shared/ # row decoders, types, prepared statements, connection poolThe user-facing class declaration is src/bun.js/api/sql.classes.ts. The implementation in Zig wraps the protocol parser and exposes an async query, transaction, tagged-template API.
Postgres client
The Postgres client speaks the wire protocol directly — no libpq dependency. It supports:
- Cleartext, MD5, SCRAM-SHA-256 authentication.
- TLS over uSockets/BoringSSL.
- Prepared statements with caching keyed by the SQL text.
- The
COPYprotocol for bulk import/export (in progress). - Pipelined queries — multiple statements may be in flight on one connection.
- Notification listeners (
LISTEN/NOTIFY). - Per-connection statement timeout, pool size, idle timeout.
The wire format is implemented as a state machine in src/sql/postgres/. Row decoding uses the per-column type OID to dispatch into a typed decoder (text or binary). Binary decoders cover numerics, JSON, arrays, dates, intervals, and geometric types.
MySQL client
The MySQL client targets MySQL 5.7+ and MariaDB 10+. It supports caching_sha2_password and mysql_native_password, prepared statements, and TLS. Wire format and authentication state machines are in src/sql/mysql/.
Shared layer
src/sql/shared/ holds the connection pool, the statement cache, the row decoder dispatch, and the type system shared by both clients. The pool is a max-size pool with idle eviction; checkouts wait on a ConcurrentTask.
JavaScript surface
import { sql } from 'bun';
const db = sql('postgres://user@localhost/db');
const rows = await db`SELECT * FROM users WHERE id = ${id}`;
await db.begin(async (tx) => {
await tx`INSERT INTO logs ${{ msg }}`;
});The tagged template returns a thenable that runs the query when awaited. Parameter substitution uses $1, $2, ... in Postgres and ? in MySQL — the template compiler picks the right form per dialect.
Performance
- Prepared statement cache means repeated queries skip the parse/plan phase.
- Result rows are decoded directly into JS values without an intermediate buffer.
COPY FROM STDIN/COPY TO STDOUT(Postgres) is plumbed as aReadableStream.
Integration points
- Event loop — Connection events post tasks; query results resolve promises.
- HTTP stack — Doesn't share with HTTP, but uses uSockets and BoringSSL.
- JSC bindings —
src/bun.js/api/sql.classes.tsdefines the JS shape.
Entry points for modification
- To add a Postgres type decoder, edit
src/sql/postgres/(look for theOIDdispatch table). - To add an authentication method, edit the auth state machine in the corresponding dialect directory.
- To change connection pooling, edit
src/sql/shared/.
Key source files
| File | Purpose |
|---|---|
src/sql/postgres/ |
Postgres protocol. |
src/sql/mysql/ |
MySQL protocol. |
src/sql/shared/ |
Pool, cache, decoders. |
src/bun.js/api/sql.classes.ts |
JS-visible class declaration. |
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.