npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@jawj/test-serverless

v0.6.1

Published

node-postgres for serverless environments from neon.tech

Downloads

31

Readme

@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:[email protected]/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}`;
// `post` is now { id: 12, title: 'My post', ... } (or undefined)

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:

  1. 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) => {
  // get and validate the `postId` query parameter
  const postId = parseInt(new URL(req.url).searchParams.get('postId'), 10);
  if (isNaN(postId)) return new Response('Bad request', { status: 400 });

  // query and validate the post
  const [post] = await sql`SELECT * FROM posts WHERE id = ${postId}`;
  if (!post) return new Response('Not found', { status: 404 });

  // return the post as JSON
  return new Response(JSON.stringify(post), { 
    headers: { 'content-type': 'application/json' }
  });
}

export const config = {
  runtime: 'edge',
  regions: ['iad1'],  // specify the region nearest your Neon DB
};
  1. Test and deploy
npm install -g vercel  # install vercel CLI
npx vercel env add DATABASE_URL  # paste Neon connection string, select all environments
npx vercel dev  # check working locally, then ...
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.

transaction()

Multiple queries can be issued via fetch request within a single, non-interactive transaction by using the transaction() function. This is exposed as a property on the query function.

For example:

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`,
]);

There are some additional options when using transaction().

Pool and Client

Use the Pool or Client constructors, instead of the functions described above, when you need:

  • session or interactive transaction support, and/or

  • compatibility with node-postgres, which supports query libraries like Kysely or Zapatos.

Queries using Pool and Client are carried by WebSockets. There are two key things to know about this:

  1. In Node.js and some other environments, there's no built-in WebSocket support. In these cases, supply a WebSocket constructor function.

  2. 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;  // <-- this is the key bit

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
pool.on('error', err => console.error(err));  // deal with e.g. re-connect
// ...

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 shown above (under the heading 'Deploy it') to use Pool, as follows:

import { Pool } from '@neondatabase/serverless';

// *don't* create a `Pool` or `Client` here, outside the request handler

export default async (req: Request, ctx: any) => {
  // create a `Pool` inside the request handler
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });

  // get and validate the `postId` query parameter
  const postId = parseInt(new URL(req.url).searchParams.get('postId'), 10);
  if (isNaN(postId)) return new Response('Bad request', { status: 400 });

  // query and validate the post
  const [post] = await pool.query('SELECT * FROM posts WHERE id = $1', [postId]);
  if (!post) return new Response('Not found', { status: 404 });

  // end the `Pool` inside the same request handler 
  // (unlike `await`, `ctx.waitUntil` won't hold up the response)
  ctx.waitUntil(pool.end());

  // return the post as JSON
  return new Response(JSON.stringify(post), { 
    headers: { 'content-type': 'application/json' }
  });
}

export const config = {
  runtime: 'edge',
  regions: ['iad1'],  // specify the region nearest your Neon DB
};

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';

// don't create a `Pool` or `Client` here, outside the request handler

export default async (req: Request, ctx: any) => {
  // create a `Client` inside the request handler
  const client = new Client(process.env.DATABASE_URL);
  await client.connect();

  // get and validate the `postId` query parameter
  const postId = parseInt(new URL(req.url).searchParams.get('postId'), 10);
  if (isNaN(postId)) return new Response('Bad request', { status: 400 });

  // query and validate the post
  const [post] = await client.query('SELECT * FROM posts WHERE id = $1', [postId]);
  if (!post) return new Response('Not found', { status: 404 });

  // end the `Client` inside the same request handler 
  // (unlike `await`, `ctx.waitUntil` won't hold up the response)
  ctx.waitUntil(client.end());

  // return the post as JSON
  return new Response(JSON.stringify(post), { 
    headers: { 'content-type': 'application/json' }
  });
}

export const config = {
  runtime: 'edge',
  regions: ['iad1'],  // specify the region nearest your Neon DB
};

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. 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.