postgres is a free, open source databases project written in JavaScript and released under Unlicense. It has 8,730 GitHub stars, 374 forks and 303 open issues, and was last pushed 16 days ago. On this registry it ranks #91 of 143 tracked projects in Databases, with 5 head-to-head comparisons available.

What is postgres?

Postgres.js is a full-featured PostgreSQL client for JavaScript and TypeScript runtimes — Node.js, Deno, Bun and Cloudflare — published to npm as postgres, and it is aimed at developers who need to query a PostgreSQL database from application code without adopting a heavier ORM or query builder.

What it is

Postgres.js is a database driver, not a database. It lives in the Node.js, Deno, Bun and Cloudflare JavaScript ecosystems, and its central design choice is the ES6 tagged template string: a query is written as sql\select ...`and awaited, returning aResultarray of objects that map column names to row values. The README describes it as a fast, full-featured client, and the repository topics list it as aclientanddriverforpostgres, postgresqlandcockroachdb`, under the JavaScript language and the Unlicense.

The concrete problem it replaces is hand-built query construction and manual parameter escaping. With Postgres.js, any interpolated value is serialized according to an inferred type, replaced by a PostgreSQL protocol placeholder such as $1, $2, ..., and sent to the database separately, which performs the escaping and casting. The README states plainly that this means SQL injection is not possible and that no special handling is required. It replaces the pattern of stitching strings together for dynamic queries and manually guarding against injection, and it removes the need for a separate query-builder layer for many applications.

Key capabilities

  • Queries run through the tagged template form await sql\...` -> Result[], and execute when awaited or immediately when .execute()` is called.
  • Query parameters are extracted before interpolation and sent as protocol placeholders, so values such as ${ name + '%' } and ${ age } are handled by the database rather than by string concatenation.
  • Connections accept either a postgres://username:password@host:port/database URL or an options object with host, port, database, username and password; object options override URL values and otherwise fall back to the same environment variables as psql.
  • Dynamic query support and query building features are exposed alongside the base query form.
  • Documented feature areas include transactions, listen & notify, realtime subscribe, data transformation, custom types, result array handling, reserving connections, teardown and cleanup, and error handling.
  • Numbers, bigint and numeric values have dedicated handling, and TypeScript support is documented.
  • ESM dynamic imports are supported with const { default: postgres } = await import('postgres').

Who uses it and how

  • Node.js services commonly create one instance in a module such as db.js with const sql = postgres({ /* options */ }) and import it elsewhere, so a single shared instance serves the application.
  • Applications deployed on Deno, Bun and Cloudflare Workers use the same API, since the tagline names all four runtimes as supported targets.
  • Teams that need queries assembled at runtime use the dynamic query and query building features rather than fixed prepared statements.
  • CockroachDB deployments are an indicated use, because the repository topics list cockroachdb next to postgres and postgresql.
  • Serverless and edge workloads are supported through the Cloudflare target, where a connection is created per runtime rather than through a long-lived server process.

Getting started

Install with npm install postgres, then create the client with postgres({ /* options */ }) or a postgres:// connection string. The README shows the instance created once in db.js, exported, and imported elsewhere as import sql from './db.js'.

How it compares

The facts provided name no alternative PostgreSQL client against which to position this project, so it stands alone in this registry rather than being contrasted with listed competitors. What the facts do establish is its licence, the Unlicense, which places the code in the public domain, and its distribution through npm as a library the adopter runs rather than a hosted service anyone pays for.

When to use it — and when not to

Adopters must already operate a PostgreSQL server, since this project is the client and not the database, and no storage, mail or database component is bundled or required beyond the server itself. It is a poor fit for teams looking for schema migration tooling or a full object-relational mapper, because the documented surface is a query client. The repository carries 303 open issues, which is worth weighing when picking a driver for a long-lived production system.

project readme (upstream, from github) — read inline
Fastest full PostgreSQL nodejs client

Getting started


Good UX with Postgres.js

Installation

$ npm install postgres

Usage

Create your sql database instance

// db.js
import postgres from 'postgres'

const sql = postgres({ /* options */ }) // will use psql environment variables

export default sql

Simply import for use elsewhere

// users.js
import sql from './db.js'

async function getUsersOver(age) {
  const users = await sql`
    select
      name,
      age
    from users
    where age > ${ age }
  `
  // users = Result [{ name: "Walter", age: 80 }, { name: 'Murray', age: 68 }, ...]
  return users
}


async function insertUser({ name, age }) {
  const users = await sql`
    insert into users
      (name, age)
    values
      (${ name }, ${ age })
    returning name, age
  `
  // users = Result [{ name: "Murray", age: 68 }]
  return users
}
ESM dynamic imports

The library can be used with ESM dynamic imports as well as shown here.

const { default: postgres } = await import('postgres')

Table of Contents

Connection

postgres([url], [options])

You can use either a postgres:// url connection string or the options to define your database connection properties. Options in the object will override any present in the url. Options will fall back to the same environment variables as psql.

const sql = postgres('postgres://username:password@host:port/database', {
  host                 : '',            // Postgres ip address[s] or domain name[s]
  port                 : 5432,          // Postgres server port[s]
  database             : '',            // Name of database to connect to
  username             : '',            // Username of database user
  password             : '',            // Password of database user
  ...and more
})

More options can be found in the Connection details section.

Queries

await sql`...` -> Result[]

Postgres.js utilizes Tagged template functions to process query parameters before interpolation. Using tagged template literals benefits developers by:

  1. Enforcing safe query generation
  2. Giving the sql`` function powerful utility and query building features.

Any generic value will be serialized according to an inferred type, and replaced by a PostgreSQL protocol placeholder $1, $2, .... The parameters are then sent separately to the database which handles escaping & casting.

All queries will return a Result array, with objects mapping column names to each row.

const xs = await sql`
  insert into users (
    name, age
  ) values (
    'Murray', 68
  )

  returning *
`

// xs = [{ user_id: 1, name: 'Murray', age: 68 }]

Please note that queries are first executed when awaited – or instantly by using .execute().

Query parameters

Parameters are automatically extracted and handled by the database so that SQL injection isn't possible. No special handling is necessary, simply use tagged template literals as usual.

const name = 'Mur'
    , age = 60

const users = await sql`
  select
    name,
    age
  from users
  where
    name like ${ name + '%' }
    and age > ${ age }
`
// users = [{ name: 'Murray', age: 68 }]

Be careful with quotation marks here. Because Postgres infers column types, you do not need to wrap your interpolated parameters in quotes like '${name}'. This will cause an error because the tagged template replaces ${name} with $1 in the query string, leaving Postgres to do the interpolation. If you wrap that in a string, Postgres will see '$1' and interpret it as a string as opposed to a parameter.

Dynamic column selection

const columns = ['name', 'age']

await sql`
  select
    ${ sql(columns) }
  from users
`

// Which results in:
select "name", "age" from users

Dynamic inserts

const user = {
  name: 'Murray',
  age: 68
}

await sql`
  insert into users ${
    sql(user, 'name', 'age')
  }
`

// Which results in:
insert into users ("name", "age") values ($1, $2)

// The columns can also be given with an array
const columns = ['name', 'age']

await sql`
  insert into users ${
    sql(user, columns)
  }
`

You can omit column names and simply execute sql(user) to get all the fields from the object as columns. Be careful not to allow users to supply columns that you do not want to be inserted.

Multiple inserts in one query

If you need to insert multiple rows at the same time it's also much faster to do it with a single insert. Simply pass an array of objects to sql().

const users = [{
  name: 'Murray',
  age: 68,
  garbage: 'ignore'
},
{
  name: 'Walter',
  age: 80
}]

await sql`insert into users ${ sql(users, 'name', 'age') }`

// Is translated to:
insert into users ("name", "age") values ($1, $2), ($3, $4)

// Here you can also omit column names which will use object keys as columns
await sql`insert into users ${ sql(users) }`

// Which results in:
insert into users ("name", "age") values ($1, $2), ($3, $4)

Dynamic columns in updates

This is also useful for update queries

const user = {
  id: 1,
  name: 'Murray',
  age: 68
}

await sql`
  update users set ${
    sql(user, 'name', 'age')
  }
  where user_id = ${ user.id }
`

// Which results in:
update users set "name" = $1, "age" = $2 where user_id = $3

// The columns can also be given with an array
const columns = ['name', 'age']

await sql`
  update users set ${
    sql(user, columns)
  }
  where user_id = ${ user.id }
`

Multiple updates in one query

To create multiple updates in a single query, it is necessary to use arrays instead of objects to ensure that the order of the items correspond with the column names.

const users = [
  [1, 'John', 34],
  [2, 'Jane', 27],
]

await sql`
  update users set name = update_data.name, age = (update_data.age)::int
  from (values ${sql(users)}) as update_data (id, name, age)
  where users.id = (update_data.id)::int
  returning users.id, users.name, users.age
`

Dynamic values and where in

Value lists can also be created dynamically, making where in queries simple too.

const users = await sql`
  select
    *
  from users
  where age in ${ sql([68, 75, 23]) }
`

or

const [{ a, b, c }] = await sql`
  select
    *
  from (values ${ sql(['a', 'b', 'c']) }) as x(a, b, c)
`

Building queries

Postgres.js features a simple dynamic query builder by conditionally appending/omitting query fragments. It works by nesting sql`` fragments within other sql`` calls or fragments. This allows you to build dynamic queries safely without risking sql injections through usual string concatenation.

Partial queries

const olderThan = x => sql`and age > ${ x }`

const filterAge = true

await sql`
  select
   *
  from users
  where name is not null ${
    filterAge
      ? olderThan(50)
      : sql``
  }
`
// Which results in:
select * from users where name is not null
// Or
select * from users where name is not null and age > 50

Dynamic filters

await sql`
  select
    *
  from users ${
    id
      ? sql`where user_id = ${ id }`
      : sql``
  }
`

// Which results in:
select * from users
// Or
select * from users where user_id = $1

Dynamic ordering

const id = 1
const order = {
  username: 'asc'
  created_at: 'desc'
}
await sql`
  select 
    * 
  from ticket 
  where account = ${ id }  
  order by ${
    Object.entries(order).flatMap(([column, order], i) =>
      [i ? sql`,` : sq

readme truncated — read the full docs on github

Frequently asked questions

Is postgres free to use?

postgres is open source under the Unlicense licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does postgres do?

Postgres.js - The Fastest full featured PostgreSQL client for Node.js, Deno, Bun and CloudFlare

What is postgres written in?

postgres is primarily written in JavaScript. Its source is publicly available at https://github.com/porsager/postgres, and it has 8,730 GitHub stars.