Talking to PostgreSQL without the pg package
StreetJS speaks PostgreSQL wire protocol v3 directly over node:net, with SCRAM-SHA-256 authentication and socket-level streaming — no pg, no native bindings to compile.
Almost every Node app that touches PostgreSQL installs pg. StreetJS doesn’t.
The framework implements the database client itself. That sounds extreme until
you look at what it buys you.
The wire protocol, briefly
PostgreSQL’s client/server protocol (version 3) is a well-documented, message-framed binary protocol over a TCP socket. A client:
- opens a socket (
node:net), - sends a startup message,
- completes authentication (StreetJS implements SCRAM-SHA-256),
- sends
Parse/Bind/Executefor parameterized queries, - reads
RowDescription+DataRowmessages back.
StreetJS implements exactly this, so from your code a query is just:
1
2
3
4
const { rows } = await pool.query(
'INSERT INTO items (name) VALUES ($1) RETURNING id, name',
['Widget'],
);
Parameters are always sent out-of-band (never string-concatenated), so parameterized queries are injection-safe by construction.
Why implement it instead of depending on it
- No transitive dependencies.
pgis well-maintained, but it and its helpers pull packages into every app that uses the framework. A native client keeps the core dependency-light — see Why StreetJS has so few dependencies. - No native bindings. Nothing to compile per platform; install is just JavaScript.
- Control over memory and backpressure. Because StreetJS owns the socket read loop, it applies streaming backpressure and bounded buffers — the same memory-safety discipline applied across the framework.
- Auth you can audit. SCRAM-SHA-256 is implemented in the open, in TypeScript, rather than delegated.
The same idea, everywhere
This isn’t a one-off. The official plugins apply the identical approach: native, dependency-free clients for MySQL, MongoDB (BSON + OP_MSG + SCRAM), Redis (RESP2), Kafka, and AMQP — all in the Plugin Marketplace.
When you’d want the opposite
If you need a PostgreSQL feature StreetJS’s driver doesn’t implement yet, that’s a real constraint — file an issue or an RFC. The native-driver bet is that the common path (parameterized queries, pooling, streaming, transactions) covers the overwhelming majority of application needs, and the dependency savings are worth owning that path.
Try it: npx @streetjs/cli create my-app --database postgres — see Getting Started.