The neon(...)
function returns a query function that can be used both as a tagged-template function and as an ordinary function:
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
// as a tagged-template function
const rowsA = await sql`SELECT * FROM posts WHERE id = ${postId}`;
// as an ordinary function (exactly equivalent)
const rowsB = await sql('SELECT * FROM posts WHERE id = $1', [postId]);
By default, the query function returned by neon(...)
returns only the rows resulting from the provided SQL query, and it returns them as an array of objects where the keys are column names. For example:
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
const rows = await sql`SELECT * FROM posts WHERE id = ${postId}`;
// -> [{ id: 12, title: "My post", ... }]
However, you can customise the return format of the query function using the configuration options fullResults
and arrayMode
. These options are available both on the neon(...)
function and on the query function it returns (but only when the query function is called as an ordinary function, not as a tagged-template function).
When arrayMode
is true, rows are returned as an array of arrays instead of an array of objects:
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL, { arrayMode: true });
const rows = await sql`SELECT * FROM posts WHERE id = ${postId}`;
// -> [[12, "My post", ...]]
Or, with the same effect:
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
const rows = await sql('SELECT * FROM posts WHERE id = $1', [postId], {
arrayMode: true,
});
// -> [[12, "My post", ...]]
When fullResults
is true, additional metadata is returned alongside the result rows, which are then found in the rows
property of the return value. The metadata matches what would be returned by node-postgres:
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL, { fullResults: true });
const results = await sql`SELECT * FROM posts WHERE id = ${postId}`;
/* -> {
rows: [{ id: 12, title: "My post", ... }],
fields: [
{ name: "id", dataTypeID: 23, ... },
{ name: "title", dataTypeID: 25, ... },
...
],
rowCount: 1,
rowAsArray: false,
command: "SELECT"
}
*/
Or, with the same effect:
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
const results = await sql('SELECT * FROM posts WHERE id = $1', [postId], {
fullResults: true,
});
// -> { ... same as above ... }
The fetchOptions
option can be passed to neon(...)
, the transaction
function, or the query function (if not within a transaction
function). This option takes an object that is merged with the options to the fetch
call.
For example, to increase the priority of every database fetch
request:
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL, {
fetchOptions: { priority: 'high' },
});
const rows = await sql`SELECT * FROM posts WHERE id = ${postId}`;
Or to implement a fetch
timeout:
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
const abortController = new AbortController();
const timeout = setTimeout(() => abortController.abort('timed out'), 10000);
const rows = await sql('SELECT * FROM posts WHERE id = $1', [postId], {
fetchOptions: { signal: abortController.signal },
}); // throws an error if no result received within 10s
clearTimeout(timeout);
The types
option can be passed to neon(...)
to override the default PostgreSQL type parsers provided by PgTypes
. This is useful if you want to define custom parsing behavior for specific PostgreSQL data types, allowing you to control how data is converted when retrieved from the database. Learn more in the PgTypes official documentation.
Example of usage:
import PgTypes from 'pg-types';
import { neon } from '@neondatabase/serverless';
// Define custom parsers for specific PostgreSQL types
// Parse PostgreSQL `DATE` fields as JavaScript `Date` objects
PgTypes.setTypeParser(PgTypes.builtins.DATE, (val) => new Date(val));
// Parse PostgreSQL `NUMERIC` fields as JavaScript `float` values
PgTypes.setTypeParser(PgTypes.builtins.NUMERIC, parseFloat);
// Configure the Neon client with the custom `types` parser
const sql = neon(process.env.DATABASE_URL, {
types: PgTypes, // Pass in the custom PgTypes object here
});
The authToken
option can be passed to neon(...)
to set the Authorization
header for the fetch
request. This allows you to authenticate database requests against third-party authentication providers. So, this mechanism can be used to ensure that access control and authorization are managed effectively across different systems.
Example of usage:
import { neon } from '@neondatabase/serverless';
// Retrieve the JWT token (implementation depends on your auth system)
const authToken = getAuthToken();
// Initialize the Neon client with a connection string and auth token
const sql = neon(process.env.DATABASE_URL, { authToken });
// Run a query
const posts = await sql('SELECT * FROM posts');
The transaction(queriesOrFn, options)
function is exposed as a property on the query function. It allows multiple queries to be executed within a single, non-interactive transaction.
The first argument to transaction()
, queriesOrFn
, is either (1) an array of queries or (2) a non-async
function that receives a query function as its argument and returns an array of queries.
The array-of-queries case looks like this:
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
const showLatestN = 10;
const [posts, tags] = await sql.transaction(
[
sql`SELECT * FROM posts ORDER BY posted_at DESC LIMIT ${showLatestN}`,
sql`SELECT * FROM tags`,
],
{
isolationLevel: 'RepeatableRead',
readOnly: true,
},
);
Or as an example of the function case:
const [authors, tags] = await neon(process.env.DATABASE_URL).transaction(
(txn) => [txn`SELECT * FROM authors`, txn`SELECT * FROM tags`],
);
The optional second argument to transaction()
, options
, has the same keys as the options to the ordinary query function -- arrayMode
, fullResults
and fetchOptions
-- plus three additional keys that concern the transaction configuration. These transaction-related keys are: isolationMode
, readOnly
and deferrable
. They are described below. Defaults for the transaction-related keys can also be set as options to the neon
function.
The fetchOptions
option cannot be supplied for individual queries inside transaction()
, since only a single fetch
is performed for the transaction as a whole. The TypeScript types also currently do not allow arrayMode
or fullResults
options to be supplied for individual queries within transaction()
(although this does have the expected effect if the type errors are ignored).
This option selects a Postgres transaction isolation mode. If present, it must be one of: 'ReadUncommitted'
, 'ReadCommitted'
, 'RepeatableRead'
or 'Serializable'
.
If true
, this option ensures that a READ ONLY
transaction is used to execute the queries passed.
If true
(and if readOnly
is also true
, and isolationMode
is 'Serializable'
), this option ensures that a DEFERRABLE
transaction is used to execute the queries passed.
In most cases, there are two ways to set configuration options:
- Import
neonConfig
from the package and set global default options on that. - Set options on individual
Client
instances using theirneonConfig
property.
For example:
import { Client, neonConfig } from '@neondatabase/serverless';
import ws from 'ws';
// set default option for all clients
neonConfig.webSocketConstructor = ws;
// override the default option on an individual client
const client = new Client(process.env.DATABASE_URL);
client.neonConfig.webSocketConstructor = ws;
A few configuration options can only be set globally, and these are noted as such below.
Set this parameter if you're using the driver in an environment where the WebSocket
global is not defined, such as Node.js, and you need transaction or session support.
For example:
import { neonConfig } from '@neondatabase/serverless';
import ws from 'ws';
neonConfig.webSocketConstructor = ws;
If you're using @neondatabase/serverless
to connect to a Neon database, you usually won't need to touch the following configuration options. These options are intended for testing, troubleshooting, and supporting access to non-Neon Postgres instances via self-hosted WebSocket proxies.
Experimentally, when poolQueryViaFetch
is true
and no listeners for the "connect"
, "acquire"
, "release"
or "remove"
events are set on the Pool
, queries via Pool.query()
will be sent by low-latency HTTP fetch
request.
Default: currently false
(but may be true
in future).
Note: this option can only be set globally, not on an individual Client
instance.
Set fetchEndpoint
to set the server endpoint to be sent queries via http fetch.
This may be useful for local development (e.g. to set a port that's not the default 443).
Provide either the full endpoint URL, or a function that takes the database host address and port and returns the full endpoint URL (including protocol).
Default: host => 'https://' + host + '/sql'
Note: this option can only be set globally, not on an individual Client
instance.
The fetchFunction
option allows you to supply an alternative function for making http requests. The function must accept the same arguments as native fetch
.
Default: undefined
.
Note: this option can only be set globally, not on an individual Client
instance.
If connecting to a non-Neon database, the wsProxy
option should point to your WebSocket proxy. It can either be a string, which will have ?address=host:port
appended to it, or a function with the signature (host: string, port: number | string) => string
. Either way, the protocol must not be included, because this depends on other options. For example, when using the wsproxy
proxy, the wsProxy
option should look something like this:
// either:
neonConfig.wsProxy = (host, port) =>
`my-wsproxy.example.com/v1?address=${host}:${port}`;
// or (with identical effect):
neonConfig.wsProxy = 'my-wsproxy.example.com/v1';
Default: host => host + '/v2'
.
To speed up connection times, the driver will pipeline the first three messages to the database (startup, authentication and first query) if pipelineConnect
is set to "password"
. Note that this will only work if you've configured cleartext password authentication for the relevant user and database.
If your connection doesn't support password authentication, set pipelineConnect
to false
instead.
Default: "password"
.
When this option is true
, multiple network writes generated in a single iteration of the JavaScript run-loop are coalesced into a single WebSocket message. Since node-postgres sends a lot of very short messages, this may reduce TCP/IP overhead.
Default: true
.
This option disables TLS encryption in the Postgres protocol (as set via e.g. ?sslmode=require
in the connection string). Security is not compromised if used in conjunction with useSecureWebSocket = true
.
Default: true
.
This option switches between secure (the default) and insecure WebSockets.
To use experimental pure-JS encryption, set useSecureWebSocket = false
and forceDisablePgSSL = false
, and append ?sslmode=verify-full
to your database connection string.
Remember that pure-JS encryption is currently experimental and not suitable for use in production.
Default: true
.
Only when using experimental pure-JS TLS encryption, you must supply the subtls TLS library to the subtls
option like so:
import { neonConfig } from '@neondatabase/serverless';
import * as subtls from 'subtls';
neonConfig.subtls = subtls;
Default: undefined
.
Only when using experimental pure-JS TLS encryption, the rootCerts
option determines what root (certificate authority) certificates are trusted.
Its value is a string containing zero or more certificates in PEM format.
Default: ""
(the empty string).
Only when using experimental pure-JS encryption, the driver will pipeline the SSL request message and TLS Client Hello if pipelineTLS
is set to true
. Currently, this is only supported by Neon database hosts, and will fail when communicating with an ordinary Postgres or pgbouncer back-end.
Default: false
.