What is @neondatabase/serverless?
@neondatabase/serverless is an npm package designed to facilitate serverless interactions with Neon, a serverless PostgreSQL database. It provides a set of tools and utilities to connect, query, and manage PostgreSQL databases in a serverless environment, making it easier to build scalable and efficient applications.
What are @neondatabase/serverless's main functionalities?
Connecting to a Neon Database
This feature allows you to establish a connection to a Neon database using the provided connection string. The code sample demonstrates how to create a new client instance and connect to the database.
const { Client } = require('@neondatabase/serverless');
const client = new Client({
connectionString: process.env.NEON_DATABASE_URL,
});
async function connect() {
await client.connect();
console.log('Connected to Neon Database');
}
connect();
Executing SQL Queries
This feature allows you to execute SQL queries against the connected Neon database. The code sample demonstrates how to connect to the database, execute a SELECT query, and log the results.
const { Client } = require('@neondatabase/serverless');
const client = new Client({
connectionString: process.env.NEON_DATABASE_URL,
});
async function executeQuery() {
await client.connect();
const res = await client.query('SELECT * FROM users');
console.log(res.rows);
await client.end();
}
executeQuery();
Handling Transactions
This feature allows you to handle transactions in the Neon database. The code sample demonstrates how to begin a transaction, execute an insert query, commit the transaction, and handle errors by rolling back the transaction if necessary.
const { Client } = require('@neondatabase/serverless');
const client = new Client({
connectionString: process.env.NEON_DATABASE_URL,
});
async function handleTransaction() {
await client.connect();
try {
await client.query('BEGIN');
await client.query('INSERT INTO users(name) VALUES($1)', ['John Doe']);
await client.query('COMMIT');
console.log('Transaction committed');
} catch (e) {
await client.query('ROLLBACK');
console.error('Transaction rolled back', e);
} finally {
await client.end();
}
}
handleTransaction();
Other packages similar to @neondatabase/serverless
pg
The 'pg' package is a popular PostgreSQL client for Node.js. It provides a comprehensive set of features for connecting to and interacting with PostgreSQL databases. Compared to @neondatabase/serverless, 'pg' is more general-purpose and widely used, but it may require additional configuration for serverless environments.
knex
The 'knex' package is a SQL query builder for Node.js, supporting multiple database types including PostgreSQL. It provides a flexible and powerful API for building and executing SQL queries. While 'knex' offers more advanced query building capabilities, it is not specifically tailored for serverless environments like @neondatabase/serverless.
sequelize
The 'sequelize' package is a promise-based Node.js ORM for various SQL databases, including PostgreSQL. It provides a higher-level abstraction for database interactions, including model definitions and associations. Compared to @neondatabase/serverless, 'sequelize' offers more features for complex data modeling but may introduce additional overhead for simple use cases.
@neondatabase/serverless [BETA]
@neondatabase/serverless
is Neon's PostgreSQL driver for JavaScript and TypeScript. It's:
- Low-latency, thanks to message pipelining and other optimizations
- Ideal for serverless/edge deployment, using https and WebSockets in place of TCP
- A drop-in replacement for node-postgres, aka
pg
(on which it's based)
Get started
Install it
Install it with your preferred JavaScript package manager. For example:
npm install @neondatabase/serverless
Using TypeScript? No worries: types are included.
Configure it
Get your connection string from the Neon console and set it as an environment variable. Something like:
DATABASE_URL=postgres://username:password@host.neon.tech/neondb
Use it
For one-shot queries, use the neon
function. For instance:
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
const [post] = await sql`SELECT * FROM posts WHERE id = ${postId}`;
Note: interpolating ${postId}
here is safe from SQL injection.
Deploy it
Turn this example into a complete API endpoint deployed on Vercel Edge Functions at https://myapp.vercel.dev/api/post?postId=123
by following two simple steps:
- Create a new file
api/post.ts
:
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
export default async (req: Request, ctx: any) => {
const postId = parseInt(new URL(req.url).searchParams.get('postId'), 10);
if (isNaN(postId)) return new Response('Bad request', { status: 400 });
const [post] = await sql`SELECT * FROM posts WHERE id = ${postId}`;
if (!post) return new Response('Not found', { status: 404 });
return new Response(JSON.stringify(post), {
headers: { 'content-type': 'application/json' }
});
}
export const config = {
runtime: 'edge',
regions: ['iad1'],
};
- Test and deploy
npm install -g vercel
npx vercel env add DATABASE_URL
npx vercel dev
npx vercel deploy
The neon
query function has a few additional options.
Sessions, transactions, and node-postgres compatibility
A query using the neon
function, as shown above, is carried by an https fetch request.
This should work — and work fast — from any modern JavaScript environment. But you can only send one query at a time this way: sessions and transactions are not supported.
Pool
and Client
Use the Pool
or Client
constructors instead when you need:
-
session or transaction support, or
-
node-postgres compatibility, to enable query libraries like Kysely or Zapatos.
Using Pool
and Client
, queries are carried by WebSockets. There are two key things you need to know:
-
In Node.js and some other environments, there's no built-in WebSocket support. In these cases, supply a WebSocket constructor function.
-
In serverless environments such as Vercel Edge Functions or Cloudflare Workers, WebSocket connections can't outlive a single request.
That means Pool
or Client
objects must be connected, used and closed within a single request handler. Don't create them outside a request handler; don't create them in one handler and try to reuse them in another; and to avoid exhausting available connections, don't forget to close them.
These points are demonstrated in the examples below.
API
Example: Node.js with Pool.connect()
In Node.js, it takes two lines to configure WebSocket support. For example:
import { Pool, neonConfig } from '@neondatabase/serverless';
import ws from 'ws';
neonConfig.webSocketConstructor = ws;
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
pool.on('error', err => console.error(err));
const client = await pool.connect();
try {
await client.query('BEGIN');
const { rows: [{ id: postId }] } = await client.query('INSERT INTO posts (title) VALUES ($1) RETURNING id', ['Welcome']);
await client.query('INSERT INTO photos (post_id, url) VALUES ($1, $2)', [postId, 's3.bucket/photo/url']);
await client.query('COMMIT');
} catch (err) {
await client.query('ROLLBACK');
throw err;
} finally {
client.release();
}
await pool.end();
Other WebSocket libraries are available. For example, you could replace ws
in the above example with undici
:
import { WebSocket } from 'undici';
neonConfig.webSocketConstructor = WebSocket;
Example: Vercel Edge Function with Pool.query()
We can rewrite the Vercel Edge Function above to use Pool
, as follows:
import { Pool } from '@neondatabase/serverless';
export default async (req: Request, ctx: any) => {
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const postId = parseInt(new URL(req.url).searchParams.get('postId'), 10);
if (isNaN(postId)) return new Response('Bad request', { status: 400 });
const [post] = await pool.query('SELECT * FROM posts WHERE id = $1', [postId]);
if (!post) return new Response('Not found', { status: 404 });
ctx.waitUntil(pool.end());
return new Response(JSON.stringify(post), {
headers: { 'content-type': 'application/json' }
});
}
export const config = {
runtime: 'edge',
regions: ['iad1'],
};
Note: we don't actually use the pooling capabilities of Pool
in this example. But it's slightly briefer than using Client
and, because Pool.query
is designed for one-shot queries, we may in future automatically route these queries over https for lower latency.
Example: Vercel Edge Function with Client
Using Client
instead, the example looks like this:
import { Client } from '@neondatabase/serverless';
export default async (req: Request, ctx: any) => {
const client = new Client(process.env.DATABASE_URL);
await client.connect();
const postId = parseInt(new URL(req.url).searchParams.get('postId'), 10);
if (isNaN(postId)) return new Response('Bad request', { status: 400 });
const [post] = await client.query('SELECT * FROM posts WHERE id = $1', [postId]);
if (!post) return new Response('Not found', { status: 404 });
ctx.waitUntil(client.end());
return new Response(JSON.stringify(post), {
headers: { 'content-type': 'application/json' }
});
}
export const config = {
runtime: 'edge',
regions: ['iad1'],
};
More examples
These repos show how to use @neondatabase/serverless
with a variety of environments and tools:
Bring your own Postgres database
This package comes configured to connect to a Neon database over a secure (wss:
) WebSocket. But you can also use it to connect to your own Postgres instances if you run your own WebSocket proxy.
Open-source
This code is released under the MIT license.
Feedback and support
Please visit Neon Community or Support.