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:
| Variable | What it is | Use it for |
|---|---|---|
DATABASE_URL | Pooled connection string | Your app's queries |
DATABASE_URL_UNPOOLED | Direct connection string | Tools 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
-
Install the integration from the linked
beachheadfolder. Answer the prompts and choose the free plan; a browser tab may open for you to accept Neon's terms.vercel install neonOne 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.” -
See what appeared.
vercel env lsDATABASE_URLand its relatives are listed for Production, Preview and Development. You did not add any of them. -
Add the driver and one route.
npm install @neondatabase/serverlessapp/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 }); } -
Try it locally. Run
npm run devand openlocalhost:3000/api/db. You get a timestamp./api/healthnow reports"hasDatabaseUrl":true. -
Predict, then ship. Before you push, open your production
/api/health.What does
hasDatabaseUrlsay 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 pushWhen the new deployment is ready, production
/api/healthsaystrueand/api/dbreturns the time. That is the win. -
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?
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 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…
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?
“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.