The most surprising thing about Vercel Postgres with Neon is that it’s not just another managed Postgres instance; it’s a serverless database designed to scale to zero and then instantly back up, making it the perfect fit for the ephemeral nature of serverless functions.

Let’s see it in action. Imagine a simple Next.js app with a pages/api/users.js endpoint that fetches user data from our Vercel Postgres database.

// pages/api/users.js
import { sql } from '@vercel/postgres';

export default async function handler(req, res) {
  try {
    const result = await sql`SELECT * FROM users;`;
    res.status(200).json({ users: result.rows });
  } catch (error) {
    console.error('Error fetching users:', error);
    res.status(500).json({ error: 'Failed to fetch users' });
  }
}

When this API route is invoked for the first time after a period of inactivity, Neon’s serverless architecture spins up a compute branch. This involves a few steps:

  1. Connection Pooling: Vercel’s @vercel/postgres SDK establishes a connection. Neon’s connection pooler receives this request.
  2. Branch Activation: If no active compute branches exist for this project/database, Neon provisions a new one. This is the "cold start" moment. It’s not a full VM boot, but rather starting up the necessary processes to handle queries.
  3. Query Execution: Once the compute branch is ready, the SELECT * FROM users; query is executed against the database.
  4. Response: The results are streamed back through the connection pooler and the SDK to your Next.js API route.

Subsequent requests within a short timeframe will hit an already warm compute branch, resulting in near-instantaneous query execution. When traffic dies down, Neon automatically scales down the compute branch, potentially to zero, saving costs.

The magic behind this lies in Neon’s architecture, which separates storage (using a distributed log) from compute. This allows for independent scaling and the ability to spin compute resources up and down on demand. Vercel integrates this seamlessly by providing the @vercel/postgres SDK, which handles connection management and automatically injects the correct Neon connection string (including the crucial connection_string and sslmode=require parameters) into your environment variables.

Here’s a typical Neon connection string you’d see in your Vercel project’s environment variables:

postgresql://<user>:<password>@ep-your-cluster-id.region.aws.neon.tech:5432/mydatabase?sslmode=require

The key components are:

  • postgresql://: The protocol.
  • <user>:<password>: Your Neon database user credentials.
  • ep-your-cluster-id.region.aws.neon.tech: The endpoint for your Neon compute branch. The ep- prefix signifies a serverless endpoint.
  • :5432: The default PostgreSQL port.
  • /mydatabase: The name of your database.
  • ?sslmode=require: Crucial for secure connections, especially in serverless environments.

On the Neon side, you’d typically create a project, then a database within that project. You can then generate a primary Neon connection string from the Neon console. Vercel’s integration simplifies this by automatically creating a new Neon project and database when you add Vercel Postgres to your project, and then populating the POSTGRES_URL environment variable. You can also link an existing Neon project by providing its connection details.

When you create a table, for example, a simple users table:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL
);

And then insert some data:

// pages/api/addUser.js
import { sql } from '@vercel/postgres';

export default async function handler(req, res) {
  const { name, email } = req.body;
  try {
    await sql`INSERT INTO users (name, email) VALUES (${name}, ${email});`;
    res.status(200).json({ message: 'User added successfully' });
  } catch (error) {
    console.error('Error adding user:', error);
    res.status(500).json({ error: 'Failed to add user' });
  }
}

This code demonstrates how the @vercel/postgres SDK abstracts away the complexities of managing connections to the serverless endpoint. It handles the handshake with Neon, ensures a connection is available (either existing or newly provisioned), and executes your SQL queries.

What most people don’t realize is how Neon’s branching strategy can be leveraged for development workflows. You can create feature branches in Neon that mirror your Git branches. When you deploy a new Git branch to Vercel, you can configure Vercel to automatically create a corresponding Neon branch. This allows each developer or deployment to have their own isolated database environment, complete with its own schema and data, without interfering with others. This isolation is achieved through Neon’s ability to create lightweight, copy-on-write branches from a shared storage layer, making it incredibly efficient.

The next hurdle you’ll likely encounter is managing schema migrations in a serverless database environment, especially when dealing with multiple concurrent deployments.

Want structured learning?

Take the full Vercel course →