Vercel Hobby · Beachhead course

Lesson 5 of 6 · about 20 minutes

A database without copy-pasting credentials

The win Your production URL returns the current time from a Postgres database, and you never saw, typed or pasted its password.

First, recall

Which environments can hold a Secret, and what did you do about the third?

Production and Preview only. Development got its own separate key. (Lesson 4)

A key has leaked. Say the rotation order.

New key, update Vercel, redeploy, check it works, then revoke the old key.

What is the Hobby plan's maximum run time for one function?

300 seconds. (Lesson 1)

The idea: let the provider write the variables

In Lesson 4 you carried a key from one website to another by hand. For databases there is a shorter path. A Marketplace integration creates the database and writes its connection details straight into your project's environment variables. The password goes from the provider to Vercel without passing through you.

This lesson uses Neon, a Postgres provider. It gives your project several variables. Two matter:

VariableWhat it isUse it for
DATABASE_URLPooled connection stringYour app's queries
DATABASE_URL_UNPOOLEDDirect connection stringTools that need a direct connection, such as migrations

Functions start and stop constantly, and each one opens its own connection. The pooled URL puts a pooler in front of Postgres so those short-lived connections do not exhaust it. Your route uses DATABASE_URL.

Do it

  1. Install the integration from the linked beachhead folder. Answer the prompts and choose the free plan; a browser tab may open for you to accept Neon's terms.

    vercel install neon

    One command “installs the integration if it isn't already on your team, provisions the resource, connects it to the currently linked project, and runs vercel env pull.”

  2. See what appeared.

    vercel env ls

    DATABASE_URL and its relatives are listed for Production, Preview and Development. You did not add any of them.

  3. Add the driver and one route.

    npm install @neondatabase/serverless

    app/api/db/route.ts

    import { neon } from "@neondatabase/serverless";
    
    export async function GET() {
      if (!process.env.DATABASE_URL) {
        return Response.json(
          { error: "DATABASE_URL is not set in this environment" },
          { status: 500 },
        );
      }
    
      const sql = neon(process.env.DATABASE_URL);
      const rows = await sql`SELECT now() AS server_time`;
    
      return Response.json({ serverTime: rows[0].server_time });
    }
  4. Try it locally. Run npm run dev and open localhost:3000/api/db. You get a timestamp. /api/health now reports "hasDatabaseUrl":true.

  5. Predict, then ship. Before you push, open your production /api/health.

    What does hasDatabaseUrl say in production right now, and why?

    false. The variables were added after that deployment was created. “Existing deployments do not get new or changed variables.”

    git add -A
    git commit -m "Add database probe"
    git push

    When the new deployment is ready, production /api/health says true and /api/db returns the time. That is the win.

  6. Look at the database from the dashboard. Open the project, go to the Storage tab, select the database, open its Database section and choose the Query tab. Run SELECT 1;. You can inspect and edit data here without installing a database client.

One database, three environments By default the install connects the same resource to Production, Preview and Development. Treat your laptop as connected to production data until you have arranged otherwise. Two ways to separate them, for a later session: Neon's preview branching, which gives each Preview deployment its own copy, or a second database connected to Development only.

Where this leaves the app

The beachhead now has the two things most first apps need: a model it can call and a place to keep data. Both credentials live in Vercel's environment variables, scoped per environment, and neither is in your repository.

Check yourself

After vercel install neon finishes, who put the database password into your Vercel project?

  • You, during the CLI prompts
  • Nobody; the integration injected it
  • You, in the Neon dashboard

The integration “automatically injects credentials into your projects as environment variables.” Fewer hands on a secret means fewer places for it to leak. Source

Which variable should a route running as a Vercel Function use for its queries?

  • DATABASE_URL
  • DATABASE_URL_UNPOOLED
  • PGHOST_UNPOOLED

DATABASE_URL is the pooled connection string. Functions open many short connections, and pooling is the documented practice for serverless. The unpooled URL is for migrations. Source

You connected the database five minutes ago. Yesterday's production deployment…

  • picked them up at runtime
  • restarted with the new variables
  • still lacks the new variables

The same rule as Lesson 3, in new clothes: “Existing deployments do not get new or changed variables. Create a new deployment after you connect a resource.” Source

With no --environment flag, which environments does vercel install neon connect the database to?

  • Only the Production environment
  • Production, Preview, and Development
  • Production and Preview only

“If you omit the option, the commands connect production, preview, and development.” Convenient, and the reason for the warning above about shared data. Source

Read this Storage on Vercel Marketplace. Read “Getting started” and “Best practices”; skip the Custom Environment section, which is Pro-only.

Ask your teacher Want Supabase or Upstash instead of Neon, or a first table and a migration? Ask in your Claude Code session; the pattern is the same and the variable names differ.