### Install @neondatabase/serverless Source: https://github.com/neondatabase/serverless/blob/main/README.md Commands to install the driver using npm or bun. ```bash npm install @neondatabase/serverless ``` ```bash bunx jsr add @neon/serverless ``` -------------------------------- ### Define DATABASE_URL environment variable Source: https://github.com/neondatabase/serverless/blob/main/README.md Example format for the Neon connection string. ```text DATABASE_URL="postgres://username:password@host.neon.tech/neondb" ``` -------------------------------- ### Configure Postgres and Deploy wsproxy Source: https://github.com/neondatabase/serverless/blob/main/DEPLOY.md Install PostgreSQL, configure authentication, and set up the wsproxy service as a systemd unit. ```bash sudo su # do this all as root export HOSTDOMAIN=ws.example.com # edit the domain name for your case # if required: install postgres + create a password-auth user apt install -y postgresql echo 'create database wstest; create user wsclear; grant all privileges on database wstest to wsclear;' | sudo -u postgres psql sudo -u postgres psql # and run: \password wsclear perl -pi -e 's/^# IPv4 local connections:\n/# IPv4 local connections:\nhost all wsclear 127.0.0.1\/32 password\n/' /etc/postgresql/14/main/pg_hba.conf service postgresql restart # install wsproxy adduser wsproxy --disabled-login sudo su wsproxy cd git clone https://github.com/neondatabase/wsproxy.git cd wsproxy go build exit echo " [Unit] Description=wsproxy [Service] Type=simple Restart=always RestartSec=5s User=wsproxy Environment=LISTEN_PORT=:6543 ALLOW_ADDR_REGEX='^${HOSTDOMAIN}:5432\$' ExecStart=/home/wsproxy/wsproxy/wsproxy [Install] WantedBy=multi-user.target " > /lib/systemd/system/wsproxy.service systemctl enable wsproxy service wsproxy start ``` -------------------------------- ### Deploy using Vercel CLI Source: https://github.com/neondatabase/serverless/blob/main/README.md Commands to install the Vercel CLI, configure environment variables, and deploy. ```bash 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 ``` -------------------------------- ### Install specific branch or commit via npm Source: https://github.com/neondatabase/serverless/blob/main/DEVELOP.md Use this command to install a specific branch or commit directly from the GitHub repository. ```bash npm install @neondatabase/serverless@github:neondatabase/serverless#BRANCH_OR_COMMIT ``` -------------------------------- ### Deploy API endpoint on Vercel Edge Functions Source: https://github.com/neondatabase/serverless/blob/main/README.md Example implementation of an edge-compatible API route using the Neon driver. ```javascript 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 }; ``` -------------------------------- ### Configure Nginx as TLS Proxy Source: https://github.com/neondatabase/serverless/blob/main/DEPLOY.md Install Nginx and Certbot to provide TLS termination for the WebSocket proxy. ```bash apt install -y golang nginx certbot python3-certbot-nginx echo "127.0.0.1 ${HOSTDOMAIN}" >> /etc/hosts echo " server { listen 80; listen [::]:80; server_name ${HOSTDOMAIN}; location / { proxy_pass http://127.0.0.1:6543/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection Upgrade; proxy_set_header Host $host; } } " > /etc/nginx/sites-available/wsproxy ln -s /etc/nginx/sites-available/wsproxy /etc/nginx/sites-enabled/wsproxy certbot --nginx -d ${HOSTDOMAIN} echo " server { server_name ${HOSTDOMAIN}; location / { proxy_pass http://127.0.0.1:6543/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection Upgrade; proxy_set_header Host $host; } listen [::]:80 ipv6only=on; listen 80; listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/${HOSTDOMAIN}/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/${HOSTDOMAIN}/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } " > /etc/nginx/sites-available/wsproxy service nginx restart ``` -------------------------------- ### Configure Pure-JS TLS with subtls Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md When using experimental pure-JS TLS encryption, supply the subtls library to the neonConfig.subtls option. Ensure subtls is installed. ```typescript import { neonConfig } from '@neondatabase/serverless'; import * as subtls from 'subtls'; neonConfig.subtls = subtls; ``` -------------------------------- ### Global and Client-Specific Configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Demonstrates how to set global default options using `neonConfig` and override them on individual `Client` instances. ```APIDOC ## Global and Client-Specific Configuration ### Description This section illustrates the two primary methods for configuring the Neon Serverless driver: setting global defaults via `neonConfig` and applying specific configurations to individual `Client` instances. ### Usage 1. **Global Defaults**: Import `neonConfig` and modify its properties to set default options for all clients. 2. **Client-Specific Overrides**: Access the `neonConfig` property of a `Client` instance to override global defaults for that specific client. ### Example ```javascript import { Client, neonConfig } from '@neondatabase/serverless'; import ws from 'ws'; // Set a global default option neonConfig.webSocketConstructor = ws; // Create a client and override the default option const client = new Client(process.env.DATABASE_URL); client.neonConfig.webSocketConstructor = ws; ``` **Note**: Some advanced configuration options can only be set globally. ``` -------------------------------- ### Upgrade Ubuntu System Source: https://github.com/neondatabase/serverless/blob/main/DEPLOY.md Ensure the system is running Ubuntu 22.04 to meet Go version requirements. ```bash sudo su # do this all as root apt update -y && apt upgrade -y && apt dist-upgrade -y apt autoremove -y && apt autoclean -y apt install -y update-manager-core do-release-upgrade # and answer yes to all defaults ``` -------------------------------- ### Configure neonConfig globally and per-client Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Demonstrates setting default options globally via neonConfig and overriding them on specific Client instances. ```javascript 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; ``` -------------------------------- ### Compose SQL queries Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Demonstrates how to compose SQL queries using template literals. ```javascript const whereClause = sql`WHERE id = ${postId}`; const [post] = await sql`SELECT * FROM posts ${whereClause}`; ``` -------------------------------- ### Configure package.json for node-postgres compatibility Source: https://github.com/neondatabase/serverless/blob/main/README.md Use overrides to replace node-postgres with the Neon driver in existing projects. ```json "dependencies": { "pg": "npm:@neondatabase/serverless@^1.0.0" }, "overrides": { "pg": "npm:@neondatabase/serverless@^1.0.0" } ``` -------------------------------- ### neon() function configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md The neon() function initializes a database connection and supports configuration options to modify how queries are executed and how results are returned. ```APIDOC ## neon(connectionString, options) ### Description Initializes the Neon serverless driver with a database connection string and optional configuration settings. ### Parameters #### Request Body - **connectionString** (string) - Required - The database connection URL. - **options** (object) - Optional - Configuration object containing: - **arrayMode** (boolean) - If true, returns rows as an array of arrays. - **fullResults** (boolean) - If true, returns metadata alongside the result rows. - **fetchOptions** (object) - Custom options merged with the underlying fetch call. ### Request Example const sql = neon(process.env.DATABASE_URL, { arrayMode: true, fullResults: false }); ### Response #### Success Response (200) - **rows** (array) - The result set of the query. - **fields** (array) - Metadata about columns (if fullResults is true). - **rowCount** (number) - Number of rows returned (if fullResults is true). ``` -------------------------------- ### fetchEndpoint Configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Explains how to configure the `fetchEndpoint` option to specify the server endpoint for HTTP fetch requests. ```APIDOC ## `fetchEndpoint` Configuration ### Description Use `fetchEndpoint` to define the server endpoint for queries sent via HTTP `fetch`. This is particularly useful for local development or when connecting to non-standard ports. ### Method Set globally via `neonConfig.fetchEndpoint`. ### Parameters - **fetchEndpoint** (string | (host: string, port: number | string) => string) - Optional - The URL of the server endpoint or a function that returns the URL. ### Default Value `host => 'https://' + host + '/sql'` **Note**: This option can only be set globally. ``` -------------------------------- ### wsProxy Configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Details the `wsProxy` option for connecting to non-Neon Postgres instances via a WebSocket proxy. ```APIDOC ## `wsProxy` Configuration ### Description When connecting to a non-Neon Postgres instance, the `wsProxy` option should specify the URL of your WebSocket proxy. It can be a string or a function that generates the URL. The protocol should not be included as it depends on other settings. ### Method Set globally via `neonConfig.wsProxy`. ### Parameters - **wsProxy** (string | (host: string, port: number | string) => string) - Optional - The WebSocket proxy endpoint. ### Example ```javascript // Using a string neonConfig.wsProxy = 'my-wsproxy.example.com/v1'; // Using a function neonConfig.wsProxy = (host, port) => `my-wsproxy.example.com/v1?address=${host}:${port}`; ``` ### Default Value `host => host + '/v2'` **Note**: This option can only be set globally. ``` -------------------------------- ### pipelineConnect Configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Explains the `pipelineConnect` option for optimizing connection times by pipelining initial database messages. ```APIDOC ## `pipelineConnect` Configuration ### Description To accelerate connection times, the driver can pipeline the first three messages (startup, authentication, and the first query) if `pipelineConnect` is set to `"password"`. This functionality requires cleartext password authentication to be configured. If password authentication is not supported, set this option to `false`. ### Method Set globally via `neonConfig.pipelineConnect`. ### Parameters - **pipelineConnect** ("password" | false) - Optional - Enables or disables message pipelining during connection. ### Default Value `"password"` **Note**: This option can only be set globally. ``` -------------------------------- ### Initialize and execute queries with neon() Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Basic usage of the neon() function to create a tagged-template query function and execute a SQL query. ```typescript 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", ... }] ``` -------------------------------- ### Node.js Pool with Transactions Source: https://github.com/neondatabase/serverless/blob/main/README.md Use `Pool.connect()` to obtain a client for interactive transactions. Remember to release the client using `client.release()` and end the pool with `pool.end()` when done. ```javascript 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(); ``` -------------------------------- ### Configure wsProxy for non-Neon databases Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Sets the WebSocket proxy endpoint using either a string or a function to handle host and port formatting. ```javascript // either: neonConfig.wsProxy = (host, port) => `my-wsproxy.example.com/v1?address=${host}:${port}`; // or (with identical effect): neonConfig.wsProxy = 'my-wsproxy.example.com/v1'; ``` -------------------------------- ### Configure neonConfig Global Settings Source: https://context7.com/neondatabase/serverless/llms.txt Sets global defaults for WebSocket constructors, fetch endpoints, and connection behavior. Required for environments like Node.js v21 and earlier. ```javascript import { neonConfig, Client, Pool } from '@neondatabase/serverless'; import ws from 'ws'; // WebSocket constructor (required for Node.js v21 and earlier) neonConfig.webSocketConstructor = ws; // Or use undici's WebSocket import { WebSocket } from 'undici'; neonConfig.webSocketConstructor = WebSocket; // Custom fetch endpoint (for self-hosted proxy or local development) neonConfig.fetchEndpoint = (host, port) => `https://${host}:${port}/sql`; // Use fetch for Pool.query() when possible (experimental) neonConfig.poolQueryViaFetch = true; // Custom fetch function neonConfig.fetchFunction = async (url, options) => { console.log('Fetching:', url); return fetch(url, options); }; // WebSocket proxy for non-Neon databases neonConfig.wsProxy = (host, port) => `wss://my-proxy.example.com/v1?address=${host}:${port}`; // Per-client configuration const client = new Client(process.env.DATABASE_URL); client.neonConfig.pipelineConnect = 'password'; // Enable connection pipelining client.neonConfig.coalesceWrites = true; // Combine multiple writes await client.connect(); ``` -------------------------------- ### fetchFunction Configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Describes the `fetchFunction` option, which allows providing a custom function for making HTTP requests. ```APIDOC ## `fetchFunction` Configuration ### Description The `fetchFunction` option allows you to supply a custom function for executing HTTP requests. This function must adhere to the same signature as the native `fetch` API. ### Method Set globally via `neonConfig.fetchFunction`. ### Parameters - **fetchFunction** (any) - Optional - A custom function for making HTTP requests. ### Default Value `undefined` **Note**: This option can only be set globally. ``` -------------------------------- ### Implement JWT Authentication with authToken Source: https://context7.com/neondatabase/serverless/llms.txt Enables JWT-based authentication using static tokens, dynamic functions, or async providers. Supports per-query overrides. ```javascript import { neon } from '@neondatabase/serverless'; // Static token const sql = neon(process.env.DATABASE_URL, { authToken: 'your-jwt-token-here', }); // Dynamic token via function const sqlDynamic = neon(process.env.DATABASE_URL, { authToken: () => getAuthTokenFromProvider(), }); // Async token function const sqlAsync = neon(process.env.DATABASE_URL, { authToken: async () => { const response = await fetch('https://auth.example.com/token'); const { token } = await response.json(); return token; }, }); // Per-query auth token override const sqlBase = neon(process.env.DATABASE_URL); const userPosts = await sqlBase.query( 'SELECT * FROM posts WHERE user_id = current_user_id()', [], { authToken: userSpecificToken } ); ``` -------------------------------- ### Execute queries with numbered placeholders Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Use the query() method to execute SQL strings with numbered placeholders instead of template literals. ```javascript const q = 'SELECT * FROM posts WHERE id = $1'; const [post] = await sql.query(q, [postId]); ``` -------------------------------- ### Neon Client Configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Configuration options for the neon client including custom type parsers and authentication tokens. ```APIDOC ## Configuration Options ### Description Configure the Neon client with custom PostgreSQL type parsers or authentication tokens for secure database access. ### Parameters - **types** (CustomTypesConfig) - Optional - Override default PostgreSQL type parsers using PgTypes. - **authToken** (string | () => Promise | string) - Optional - Set the Authorization header for fetch requests. ### Request Example ```typescript const sql = neon(process.env.DATABASE_URL, { types: { ... }, authToken: 'your-jwt-token' }); ``` ``` -------------------------------- ### REST API Endpoint with neon() Source: https://context7.com/neondatabase/serverless/llms.txt Uses the neon() function for optimal latency in a Vercel Edge Function. Requires DATABASE_URL to be set in environment variables. ```javascript // api/posts/[id].ts import { neon } from '@neondatabase/serverless'; const sql = neon(process.env.DATABASE_URL); export default async function handler(req, ctx) { const url = new URL(req.url); const postId = parseInt(url.pathname.split('/').pop(), 10); if (isNaN(postId)) { return new Response(JSON.stringify({ error: 'Invalid post ID' }), { status: 400, headers: { 'Content-Type': 'application/json' }, }); } try { const [post] = await sql` SELECT p.*, u.name as author_name FROM posts p JOIN users u ON p.author_id = u.id WHERE p.id = ${postId} `; if (!post) { return new Response(JSON.stringify({ error: 'Post not found' }), { status: 404, headers: { 'Content-Type': 'application/json' }, }); } return new Response(JSON.stringify(post), { status: 200, headers: { 'Content-Type': 'application/json', 'Cache-Control': 'public, max-age=60', }, }); } catch (err) { console.error('Database error:', err); return new Response(JSON.stringify({ error: 'Internal server error' }), { status: 500, headers: { 'Content-Type': 'application/json' }, }); } } export const config = { runtime: 'edge', regions: ['iad1'], // Deploy near your Neon database region }; ``` -------------------------------- ### sql.query() method Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Executes a SQL query using a string and parameters, allowing for dynamic query execution and per-query configuration. ```APIDOC ## sql.query(query, params, options) ### Description Executes a raw SQL query string with numbered placeholders ($1, $2, etc.) and optional configuration overrides. ### Parameters #### Request Body - **query** (string) - Required - The SQL query string. - **params** (array) - Required - An array of values to bind to the placeholders. - **options** (object) - Optional - Configuration overrides (arrayMode, fullResults, fetchOptions). ### Request Example const [post] = await sql.query('SELECT * FROM posts WHERE id = $1', [postId], { arrayMode: true }); ### Response #### Success Response (200) - **result** (any) - The query result based on the provided configuration. ``` -------------------------------- ### Implement Vercel Edge Function with Client Source: https://github.com/neondatabase/serverless/blob/main/README.md Instantiate the Client inside the request handler and use ctx.waitUntil to ensure the connection is closed after the response is sent. ```javascript 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(); try { // 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 { rows: [post] } = await client.query('SELECT * FROM posts WHERE id = $1', [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' } }); } finally { // end the `Client` inside the same request handler // (unlike `await`, `ctx.waitUntil` won't hold up the response) ctx.waitUntil(client.end()); } } export const config = { runtime: 'edge', regions: ['iad1'], // specify the region nearest your Neon DB }; ``` -------------------------------- ### Configure neon() result formats Source: https://context7.com/neondatabase/serverless/llms.txt Customize query output using arrayMode for array-based rows or fullResults for node-postgres compatible metadata. ```javascript import { neon } from '@neondatabase/serverless'; // Default: rows as objects const sql = neon(process.env.DATABASE_URL); const rows = await sql`SELECT id, title FROM posts LIMIT 2`; // -> [{ id: 1, title: 'First' }, { id: 2, title: 'Second' }] // arrayMode: rows as arrays (more compact) const sqlArray = neon(process.env.DATABASE_URL, { arrayMode: true }); const arrayRows = await sqlArray`SELECT id, title FROM posts LIMIT 2`; // -> [[1, 'First'], [2, 'Second']] // fullResults: include metadata like node-postgres const sqlFull = neon(process.env.DATABASE_URL, { fullResults: true }); const result = await sqlFull`SELECT id, title FROM posts LIMIT 2`; // -> { // command: 'SELECT', // rowCount: 2, // rowAsArray: false, // fields: [ // { name: 'id', dataTypeID: 23 }, // { name: 'title', dataTypeID: 25 } // ], // rows: [{ id: 1, title: 'First' }, { id: 2, title: 'Second' }] // } // Options can also be passed per-query via query() const sqlDefault = neon(process.env.DATABASE_URL); const perQueryResult = await sqlDefault.query( 'SELECT id, title FROM posts WHERE id = $1', [1], { arrayMode: true, fullResults: true } ); // -> { command: 'SELECT', rows: [[1, 'First Post']], fields: [...], ... } ``` -------------------------------- ### poolQueryViaFetch Configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Details the experimental `poolQueryViaFetch` option, which enables sending queries via HTTP fetch requests under specific conditions. ```APIDOC ## `poolQueryViaFetch` Configuration ### Description This experimental option, when enabled (`true`), allows queries made through `Pool.query()` to be sent over low-latency HTTP `fetch` requests, provided no event listeners for `"connect"`, `"acquire"`, `"release"`, or `"remove"` are set on the `Pool`. This is intended for testing and troubleshooting. ### Method Set globally via `neonConfig.poolQueryViaFetch`. ### Parameters - **poolQueryViaFetch** (boolean) - Optional - If `true`, enables query execution via HTTP fetch. ### Default Value Currently `false`, but subject to change. **Note**: This option can only be set globally. ``` -------------------------------- ### Configure fetchOptions for Requests Source: https://context7.com/neondatabase/serverless/llms.txt Passes additional options to the underlying fetch call to manage request priority, caching, and timeouts via AbortController. ```javascript import { neon } from '@neondatabase/serverless'; // Set global fetch options const sql = neon(process.env.DATABASE_URL, { fetchOptions: { priority: 'high', cache: 'no-store', }, }); // Implement query timeout with AbortController const sqlTimeout = neon(process.env.DATABASE_URL); async function queryWithTimeout(query, params, timeoutMs = 5000) { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), timeoutMs); try { const result = await sqlTimeout.query(query, params, { fetchOptions: { signal: controller.signal }, }); return result; } catch (err) { if (err.name === 'AbortError') { throw new Error(`Query timed out after ${timeoutMs}ms`); } throw err; } finally { clearTimeout(timeout); } } // Usage const posts = await queryWithTimeout( 'SELECT * FROM posts WHERE category = $1', ['tech'], 3000 // 3 second timeout ); ``` -------------------------------- ### webSocketConstructor Configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Explains the `webSocketConstructor` option for environments where the `WebSocket` global is not defined, such as Node.js. ```APIDOC ## `webSocketConstructor` Configuration ### Description The `webSocketConstructor` option is essential when using the driver in environments like Node.js where the global `WebSocket` object is not available. It allows you to provide a custom WebSocket implementation, which is necessary for features like transaction and session support. ### Method Set globally via `neonConfig.webSocketConstructor`. ### Parameters - **webSocketConstructor** (typeof WebSocket | undefined) - Required - The WebSocket constructor to use. ### Request Example ```javascript import { neonConfig } from '@neondatabase/serverless'; import ws from 'ws'; neonConfig.webSocketConstructor = ws; ``` ``` -------------------------------- ### Execute queries with neon() Source: https://context7.com/neondatabase/serverless/llms.txt Use the neon() function for single queries over HTTPS. It supports tagged template literals for safe parameterization and dynamic SQL construction. ```javascript import { neon } from '@neondatabase/serverless'; // Initialize the query function with your connection string const sql = neon(process.env.DATABASE_URL); // Basic tagged-template query (SQL injection safe) const postId = 123; const [post] = await sql`SELECT * FROM posts WHERE id = ${postId}`; // -> { id: 123, title: 'My Post', content: '...' } // Composable queries - build complex queries from parts const orderBy = sql`ORDER BY created_at DESC`; const limit = sql`LIMIT ${10}`; const posts = await sql`SELECT * FROM posts ${orderBy} ${limit}`; // -> [{ id: 1, ... }, { id: 2, ... }, ...] // Using query() for dynamic SQL with numbered placeholders const searchTerm = '%search%'; const results = await sql.query( 'SELECT * FROM posts WHERE title LIKE $1 OR content LIKE $2', [searchTerm, searchTerm] ); // -> [{ id: 5, title: 'Search results...', ... }] // Using unsafe() for trusted dynamic identifiers (table/column names) const tableName = 'posts'; // Must be trusted, not user input! const columnName = 'title'; const rows = await sql`SELECT ${sql.unsafe(columnName)} FROM ${sql.unsafe(tableName)}`; // -> [{ title: 'Post 1' }, { title: 'Post 2' }] ``` -------------------------------- ### Manage WebSocket Connection Pool with Pool Source: https://context7.com/neondatabase/serverless/llms.txt The Pool class provides a node-postgres compatible connection pool. Ensure the pool is created and closed within each serverless request handler. ```javascript import { Pool, neonConfig } from '@neondatabase/serverless'; import ws from 'ws'; // Configure WebSocket for Node.js v21 and earlier neonConfig.webSocketConstructor = ws; // Create pool (in serverless: do this inside request handler) const pool = new Pool({ connectionString: process.env.DATABASE_URL }); // Simple query (no transaction) const { rows } = await pool.query('SELECT * FROM posts WHERE id = $1', [123]); // rows -> [{ id: 123, title: '...', content: '...' }] // Using pool.connect() for transactions const client = await pool.connect(); try { await client.query('BEGIN'); const { rows: [post] } = await client.query( 'INSERT INTO posts (title, content) VALUES ($1, $2) RETURNING id', ['New Post', 'Content here'] ); await client.query( 'INSERT INTO post_tags (post_id, tag_id) VALUES ($1, $2)', [post.id, 1] ); await client.query('COMMIT'); console.log('Transaction committed, post id:', post.id); } catch (err) { await client.query('ROLLBACK'); throw err; } finally { client.release(); } // Always close the pool when done await pool.end(); ``` -------------------------------- ### Direct WebSocket Connection with Client Source: https://context7.com/neondatabase/serverless/llms.txt The Client class provides a single WebSocket connection for scenarios requiring session-based features like transactions without pooling overhead. ```javascript import { Client, neonConfig } from '@neondatabase/serverless'; import ws from 'ws'; // Configure WebSocket for Node.js v21 and earlier neonConfig.webSocketConstructor = ws; // Create and connect client const client = new Client(process.env.DATABASE_URL); await client.connect(); try { // Simple query const { rows } = await client.query('SELECT NOW() as current_time'); console.log('Database time:', rows[0].current_time); // Parameterized query const { rows: users } = await client.query( 'SELECT * FROM users WHERE email = $1', ['user@example.com'] ); // Interactive transaction await client.query('BEGIN'); const { rows: [account] } = await client.query( 'SELECT balance FROM accounts WHERE id = $1 FOR UPDATE', [accountId] ); if (account.balance >= amount) { await client.query( 'UPDATE accounts SET balance = balance - $1 WHERE id = $2', [amount, accountId] ); await client.query( 'INSERT INTO transactions (account_id, amount, type) VALUES ($1, $2, $3)', [accountId, amount, 'withdrawal'] ); await client.query('COMMIT'); } else { await client.query('ROLLBACK'); throw new Error('Insufficient funds'); } } finally { await client.end(); } ``` -------------------------------- ### Execute one-shot queries Source: https://github.com/neondatabase/serverless/blob/main/README.md Use the neon function for simple queries with automatic SQL injection protection via template tags. ```javascript 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) ``` -------------------------------- ### Configure fetchOptions Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Passes custom options to the underlying fetch call, such as request priority or abort signals for timeouts. ```typescript 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}`; ``` ```typescript 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.query('SELECT * FROM posts WHERE id = $1', [postId], { fetchOptions: { signal: abortController.signal }, }); // throws an error if no result received within 10s clearTimeout(timeout); ``` -------------------------------- ### useSecureWebSocket Configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Details the `useSecureWebSocket` option for switching between secure and insecure WebSocket connections. ```APIDOC ## `useSecureWebSocket` Configuration ### Description This option controls whether to use secure (default) or insecure WebSockets. For experimental pure-JS encryption, set `useSecureWebSocket = false` and `forceDisablePgSSL = false`, and append `?sslmode=verify-full` to your database connection string. **Note**: Pure-JS encryption is experimental and not recommended for production. ### Method Set globally via `neonConfig.useSecureWebSocket`. ### Parameters - **useSecureWebSocket** (boolean) - Optional - If `true`, uses secure WebSockets; if `false`, uses insecure WebSockets. ### Default Value `true` **Note**: This option can only be set globally. ``` -------------------------------- ### Configure WebSocket in Node.js Source: https://github.com/neondatabase/serverless/blob/main/README.md In Node.js v21 and earlier, you must configure a WebSocket constructor like 'ws' for `Pool` or `Client` connections. This is not needed in newer Node.js versions. ```javascript import { Pool, neonConfig } from '@neondatabase/serverless'; // only do this in Node v21 and below import ws from 'ws'; neonConfig.webSocketConstructor = ws; ``` ```typescript import { WebSocket } from 'undici'; neonConfig.webSocketConstructor = WebSocket; ``` -------------------------------- ### forceDisablePgSSL Configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Explains the `forceDisablePgSSL` option for disabling TLS encryption in the Postgres protocol. ```APIDOC ## `forceDisablePgSSL` Configuration ### Description This option disables TLS encryption for the Postgres protocol (e.g., `?sslmode=require` in the connection string). Security is not compromised when used in conjunction with `useSecureWebSocket = true`. ### Method Set globally via `neonConfig.forceDisablePgSSL`. ### Parameters - **forceDisablePgSSL** (boolean) - Optional - If `true`, disables TLS encryption in the Postgres protocol. ### Default Value `true` **Note**: This option can only be set globally. ``` -------------------------------- ### Configure custom type parsers with neon Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Use the types option to override default PostgreSQL type parsers, allowing custom conversion logic for specific data types. ```typescript import PgTypes from 'pg-types'; import { neon } from '@neondatabase/serverless'; // Configure the Neon client with the custom `types` parser const sql = neon(process.env.DATABASE_URL, { types: { getTypeParser: ((oid, format?: any) => { // Define custom parsers for specific PostgreSQL types // Parse PostgreSQL `DATE` fields as JavaScript `Date` objects if (oid === PgTypes.builtins.DATE) { return (val: any) => new Date(val); } // Parse PostgreSQL `NUMERIC` fields as JavaScript `float` values if (oid === PgTypes.builtins.NUMERIC) { return parseFloat; } // For all other types, use the default parser return PgTypes.getTypeParser(oid, format); }) as typeof PgTypes.getTypeParser, }, }); ``` -------------------------------- ### Configure fullResults for metadata Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Enables fullResults to return query metadata alongside the result rows. ```typescript 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" } */ ``` ```typescript import { neon } from '@neondatabase/serverless'; const sql = neon(process.env.DATABASE_URL); const results = await sql.query('SELECT * FROM posts WHERE id = $1', [postId], { fullResults: true, }); // -> { ... same as above ... } ``` -------------------------------- ### Handle NeonDbError with PostgreSQL Details Source: https://context7.com/neondatabase/serverless/llms.txt This snippet shows how to catch `NeonDbError`, access specific PostgreSQL error fields like code, detail, and hint, and handle common error codes such as unique violations. ```javascript import { neon, NeonDbError } from '@neondatabase/serverless'; const sql = neon(process.env.DATABASE_URL); async function createUser(email, name) { try { const [user] = await sql` INSERT INTO users (email, name) VALUES (${email}, ${name}) RETURNING * `; return { success: true, user }; } catch (err) { if (err instanceof NeonDbError) { // Access PostgreSQL error details console.error('Database error:', { message: err.message, code: err.code, // e.g., '23505' for unique violation detail: err.detail, // e.g., 'Key (email)=(x@y.com) already exists.' hint: err.hint, constraint: err.constraint, // e.g., 'users_email_key' table: err.table, column: err.column, severity: err.severity, }); // Handle specific error codes if (err.code === '23505') { return { success: false, error: 'Email already registered' }; } if (err.code === '23503') { return { success: false, error: 'Referenced record not found' }; } } throw err; } } // Usage const result = await createUser('user@example.com', 'John Doe'); if (!result.success) { console.log('Failed:', result.error); } ``` -------------------------------- ### Execute Batch Queries with transaction() Source: https://context7.com/neondatabase/serverless/llms.txt Use the transaction method to execute multiple queries atomically in a single HTTP request. Supports both array-based query lists and function-based transaction scoping. ```javascript import { neon } from '@neondatabase/serverless'; const sql = neon(process.env.DATABASE_URL); // Array syntax: pass an array of queries const [posts, tags] = await sql.transaction([ sql`SELECT * FROM posts ORDER BY created_at DESC LIMIT 10`, sql`SELECT * FROM tags WHERE active = true`, ]); // posts -> [{ id: 1, title: '...' }, ...] // tags -> [{ id: 1, name: 'javascript' }, ...] // Function syntax: receive a transaction-scoped query function const [users, settings] = await sql.transaction(txn => [ txn`SELECT * FROM users WHERE id = ${userId}`, txn`SELECT * FROM user_settings WHERE user_id = ${userId}`, ]); // With transaction options const [inventory, order] = await sql.transaction( [ sql`UPDATE inventory SET quantity = quantity - 1 WHERE product_id = ${productId} RETURNING *`, sql`INSERT INTO orders (product_id, user_id) VALUES (${productId}, ${userId}) RETURNING *`, ], { isolationLevel: 'Serializable', // 'ReadUncommitted' | 'ReadCommitted' | 'RepeatableRead' | 'Serializable' readOnly: false, // true for read-only transactions deferrable: false, // true for deferrable serializable read-only transactions } ); // Read-only transaction for consistent reads const [snapshot1, snapshot2] = await sql.transaction( [ sql`SELECT count(*) FROM orders`, sql`SELECT sum(amount) FROM orders`, ], { isolationLevel: 'RepeatableRead', readOnly: true } ); ``` -------------------------------- ### Vercel Edge Function with Pool.query() Source: https://github.com/neondatabase/serverless/blob/main/README.md In serverless environments like Vercel Edge Functions, create `Pool` or `Client` objects within the request handler and ensure they are closed before the handler exits. Use `ctx.waitUntil(pool.end())` to close the pool without blocking the response. ```javascript 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 }); try { // 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 { rows: [post] } = await pool.query('SELECT * FROM posts WHERE id = $1', [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' } }); } finally { // end the `Pool` inside the same request handler // (unlike `await`, `ctx.waitUntil` won't hold up the response) ctx.waitUntil(pool.end()); } } export const config = { runtime: 'edge', regions: ['iad1'], // specify the region nearest your Neon DB }; ``` -------------------------------- ### coalesceWrites Configuration Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Details the `coalesceWrites` option, which combines multiple network writes into a single WebSocket message to reduce overhead. ```APIDOC ## `coalesceWrites` Configuration ### Description When `coalesceWrites` is enabled (`true`), multiple network writes generated within a single JavaScript event loop iteration are merged into a single WebSocket message. This can help reduce TCP/IP overhead, especially given the frequent short messages sent by node-postgres. ### Method Set globally via `neonConfig.coalesceWrites`. ### Parameters - **coalesceWrites** (boolean) - Optional - If `true`, coalesces multiple network writes into a single WebSocket message. ### Default Value `true` **Note**: This option can only be set globally. ``` -------------------------------- ### Authenticate Neon client requests Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Pass an authToken to the neon client to set the Authorization header for fetch requests, enabling integration with third-party auth providers. ```typescript 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`; ``` -------------------------------- ### Define Custom Type Parsers Source: https://context7.com/neondatabase/serverless/llms.txt Overrides default PostgreSQL type parsing to map database types to specific JavaScript types using pg-types. ```javascript import { neon, Pool } from '@neondatabase/serverless'; import PgTypes from 'pg-types'; // Custom type parser configuration const customTypes = { getTypeParser: (oid, format) => { // Parse DATE as JavaScript Date objects if (oid === PgTypes.builtins.DATE) { return (val) => new Date(val); } // Parse NUMERIC as JavaScript floats if (oid === PgTypes.builtins.NUMERIC) { return parseFloat; } // Parse BIGINT as JavaScript BigInt if (oid === PgTypes.builtins.INT8) { return BigInt; } // Use default parser for other types return PgTypes.getTypeParser(oid, format); }, }; // With neon() function const sql = neon(process.env.DATABASE_URL, { types: customTypes }); const [row] = await sql`SELECT '2024-01-15'::date as date_val, 123.456::numeric as numeric_val, 9007199254740993::bigint as bigint_val`; // -> { date_val: Date object, numeric_val: 123.456, bigint_val: 9007199254740993n } // With Pool const pool = new Pool({ connectionString: process.env.DATABASE_URL, types: customTypes, }); const { rows } = await pool.query('SELECT NOW()::date as today'); // -> [{ today: Date object }] ``` -------------------------------- ### Interpolate dynamic identifiers with unsafe() Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Use sql.unsafe() to safely interpolate trusted dynamic strings like table or column names into queries. ```javascript const table = condition ? 'some_posts' : 'other_posts'; const [post] = await sql`SELECT * FROM ${sql.unsafe(table)} WHERE id = ${postId}`; ``` -------------------------------- ### Set webSocketConstructor globally Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Required for environments like Node.js where the global WebSocket object is undefined. ```javascript import { neonConfig } from '@neondatabase/serverless'; import ws from 'ws'; neonConfig.webSocketConstructor = ws; ``` -------------------------------- ### transaction() function Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Execute multiple queries within a single, non-interactive transaction. ```APIDOC ## transaction(queriesOrFn, options) ### Description Allows multiple queries to be executed within a single, non-interactive transaction. ### Parameters - **queriesOrFn** (Array | Function) - Required - An array of queries or a function returning an array of queries. - **options** (Object) - Optional - Transaction configuration options. #### Transaction Options - **isolationMode** (string) - Optional - 'ReadUncommitted', 'ReadCommitted', 'RepeatableRead', or 'Serializable'. - **readOnly** (boolean) - Optional - If true, executes as a READ ONLY transaction. - **deferrable** (boolean) - Optional - If true, ensures a DEFERRABLE transaction (requires readOnly and Serializable). ### Request Example ```javascript const [posts, tags] = await sql.transaction( [sql`SELECT * FROM posts`, sql`SELECT * FROM tags`], { isolationLevel: 'RepeatableRead', readOnly: true } ); ``` ``` -------------------------------- ### Configure arrayMode for query results Source: https://github.com/neondatabase/serverless/blob/main/CONFIG.md Configures the query to return rows as arrays of values instead of objects. ```typescript 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", ...]] ``` ```typescript import { neon } from '@neondatabase/serverless'; const sql = neon(process.env.DATABASE_URL); const rows = await sql.query('SELECT * FROM posts WHERE id = $1', [postId], { arrayMode: true, }); // -> [[12, "My post", ...]] ```