Add PostgreSQL to a V0 by Vercel app using Neon Postgres from the Vercel Marketplace. Connect your Vercel project, and Vercel automatically provisions a Neon database and injects the DATABASE_URL environment variable. Use the `@neondatabase/serverless` package in Next.js API routes for HTTP-based queries optimized for serverless functions.
PostgreSQL on Vercel: The Neon Native Integration
PostgreSQL is the world's most popular open-source relational database, and it is the natural choice for V0-generated apps that need structured data storage — user records, product catalogs, orders, blog posts, or any data with relationships between tables. Vercel's native PostgreSQL solution is built on Neon, a serverless PostgreSQL platform designed specifically for the stateless, on-demand nature of serverless functions.
The Vercel Marketplace integration is the fastest path to adding a database to your V0 app. Instead of signing up for a separate database service, configuring connection strings, and manually copying credentials into Vercel, the Marketplace integration does all of this in one click. Vercel provisions a Neon database, creates a dedicated user with appropriate permissions, generates the connection string, and automatically injects it as the DATABASE_URL environment variable across all your environments — Production, Preview, and Development.
Neon's architecture is purpose-built for serverless: it uses HTTP-based queries (via the `@neondatabase/serverless` package's `neon()` function) that work perfectly with Vercel's stateless serverless functions, unlike traditional PostgreSQL drivers that rely on persistent TCP connections. Neon also provides database branching — each Vercel preview deployment gets its own database branch, so you can test schema changes in pull requests without affecting production data.
Integration method
Vercel's Marketplace integration with Neon Postgres provides one-click PostgreSQL setup directly from your Vercel project dashboard. Vercel provisions the database, automatically injects the DATABASE_URL environment variable, and handles connection management. You use the `@neondatabase/serverless` package in your Next.js API routes — no manual credential setup required.
Prerequisites
- A V0 by Vercel account at v0.dev (includes a Vercel account)
- Your V0 project deployed or connected to Vercel (use V0's Share → Publish to deploy)
- No separate database account needed — Neon account is created automatically through Vercel Marketplace
Step-by-step guide
Add Neon Postgres from the Vercel Marketplace
Add Neon Postgres from the Vercel Marketplace
The Vercel Marketplace integration makes adding PostgreSQL to your project as simple as adding an app on your phone. You do not need to create a Neon account separately, generate credentials, or copy and paste connection strings. Vercel handles the entire setup workflow. First, make sure your V0 project is deployed to Vercel. In V0, click the Share button (top right) and then Publish to Production to create your initial deployment. Once deployed, go to vercel.com and find your project in the dashboard. In your Vercel project, navigate to the Storage tab in the top navigation. This is where all Vercel-integrated data services live. Click 'Browse Marketplace' or look for the 'Add' button next to Storage. In the Marketplace, find 'Neon Serverless Postgres' and click on it. Click 'Add Integration'. Vercel will walk you through a short setup flow: 1. Choose your Neon plan (the free tier is sufficient to start — 0.5 GB storage, 10 branch databases) 2. Select which Vercel environments should have access (default is Production + Preview + Development — keep all three checked) 3. Click 'Connect' or 'Deploy' Vercel provisions the Neon database in seconds and automatically injects the following environment variables into your project: `DATABASE_URL`, `DATABASE_URL_UNPOOLED`, `PGHOST`, `PGUSER`, `PGDATABASE`, `PGPASSWORD`. The `DATABASE_URL` is the primary connection string your application code will use. You can confirm this worked by going to your project's Settings → Environment Variables. You will see all the database variables listed there with encrypted values managed by Vercel.
Pro tip: The free Neon tier on Vercel includes branching — each pull request gets its own database branch automatically. This means you can safely test schema changes in preview deployments without touching production data.
Expected result: Neon Postgres is connected to your Vercel project. The Storage tab shows your database. Settings → Environment Variables shows DATABASE_URL and related variables automatically populated.
Install @neondatabase/serverless and Create a Database Schema
Install @neondatabase/serverless and Create a Database Schema
With the database provisioned and DATABASE_URL available, install the Neon serverless client package in your Next.js project. Clone your GitHub repository locally (or work in V0's Dev Mode on paid plans). In the project root, run `npm install @neondatabase/serverless` to add the package. The `@neondatabase/serverless` package provides two ways to query Neon: - **`neon()`** — an HTTP-based query function for simple queries. Each call opens an HTTP connection, sends the query, and closes. Perfect for single queries in serverless functions where connection reuse is not possible. - **`Pool`** — a connection pool class for transactions and multiple queries that need to run in the same session. Use this when you need `BEGIN`/`COMMIT` transaction semantics. For most V0 app use cases, the `neon()` function is what you want — it is simpler, works without any connection management, and handles Neon's serverless scale-to-zero behavior automatically. Before creating API routes, set up your database schema. You can run SQL directly in the Neon Console (accessible from your Vercel project's Storage tab → Open in Neon Console) or through a migration tool. For a simple V0 app getting started quickly, running a CREATE TABLE statement directly in the Neon SQL Editor is the fastest approach. Create the tables your application needs with proper column types, primary keys, and indexes. The Neon Console has a full SQL Editor interface where you can write and execute SQL statements, browse your table structure, and view data. For simple starting schemas, this is faster than setting up a migration framework.
1-- Run in Neon Console SQL Editor to create example tables2CREATE TABLE IF NOT EXISTS users (3 id SERIAL PRIMARY KEY,4 email TEXT UNIQUE NOT NULL,5 display_name TEXT NOT NULL,6 bio TEXT DEFAULT '',7 avatar_url TEXT DEFAULT '',8 created_at TIMESTAMPTZ DEFAULT NOW()9);1011CREATE TABLE IF NOT EXISTS products (12 id SERIAL PRIMARY KEY,13 name TEXT NOT NULL,14 description TEXT,15 price NUMERIC(10, 2) NOT NULL,16 category TEXT NOT NULL,17 image_url TEXT DEFAULT '',18 created_at TIMESTAMPTZ DEFAULT NOW()19);2021-- Index for full-text search on products22CREATE INDEX IF NOT EXISTS products_search_idx23 ON products USING GIN(to_tsvector('english', name || ' ' || COALESCE(description, '')));Pro tip: Run your CREATE TABLE statements with `IF NOT EXISTS` so they are idempotent — safe to run multiple times without errors if the table already exists.
Expected result: The @neondatabase/serverless package is installed in your project. Your database tables are created and visible in the Neon Console's Tables section.
Create Next.js API Routes to Query the Database
Create Next.js API Routes to Query the Database
Now create the API routes that your V0-generated React components will call to read and write data. Each API route imports the `neon` function from `@neondatabase/serverless`, initializes it with `process.env.DATABASE_URL`, and runs SQL queries against your Neon database. Create the file `app/api/products/route.ts` for a product catalog route. The route accepts a GET request with optional `q` (search query) and `category` (filter) query parameters, builds a SQL query with those filters, and returns the results as JSON. For the `neon()` HTTP client, you initialize it once per module with the DATABASE_URL and call it as a tagged template literal: `await sql\`SELECT * FROM products\``. The tagged template literal automatically handles SQL parameter escaping — use `${variable}` inside the template and Neon will parameterize it safely, preventing SQL injection. For write operations (POST, PUT, DELETE), use the same pattern but with INSERT, UPDATE, or DELETE statements. For operations that need atomicity across multiple statements (like creating an order and updating inventory simultaneously), use the `Pool` class with explicit transactions. The `DATABASE_URL` environment variable is automatically available in your API routes because Vercel injected it during the Marketplace setup. You do not need to add it manually in `.env.local` — Vercel's CLI (if you use it) or the `vercel env pull` command can download the variables for local development. Alternatively, go to Vercel Dashboard → Settings → Environment Variables → find DATABASE_URL and copy the value into a `.env.local` file for local testing.
1// app/api/products/route.ts2import { NextRequest, NextResponse } from 'next/server';3import { neon } from '@neondatabase/serverless';45const sql = neon(process.env.DATABASE_URL!);67export async function GET(request: NextRequest) {8 const { searchParams } = new URL(request.url);9 const query = searchParams.get('q') ?? '';10 const category = searchParams.get('category') ?? '';1112 try {13 let rows;1415 if (query) {16 // Full-text search using PostgreSQL tsvector17 rows = await sql`18 SELECT id, name, description, price, category, image_url19 FROM products20 WHERE (21 to_tsvector('english', name || ' ' || COALESCE(description, ''))22 @@ plainto_tsquery('english', ${query})23 )24 ${category ? sql`AND category = ${category}` : sql``}25 ORDER BY name26 LIMIT 5027 `;28 } else {29 rows = await sql`30 SELECT id, name, description, price, category, image_url31 FROM products32 ${category ? sql`WHERE category = ${category}` : sql``}33 ORDER BY name34 LIMIT 5035 `;36 }3738 return NextResponse.json({ products: rows });39 } catch (error) {40 console.error('Database query error:', error);41 return NextResponse.json(42 { error: 'Failed to fetch products' },43 { status: 500 }44 );45 }46}4748export async function POST(request: NextRequest) {49 try {50 const body = await request.json();51 const { name, description, price, category, image_url } = body;5253 const [product] = await sql`54 INSERT INTO products (name, description, price, category, image_url)55 VALUES (${name}, ${description}, ${price}, ${category}, ${image_url})56 RETURNING *57 `;5859 return NextResponse.json({ product }, { status: 201 });60 } catch (error) {61 console.error('Insert error:', error);62 return NextResponse.json(63 { error: 'Failed to create product' },64 { status: 500 }65 );66 }67}Pro tip: Use the `neon()` tagged template literal for automatic SQL parameterization — never concatenate user input directly into SQL strings. The `${variable}` syntax inside neon() template literals is always parameterized and safe from SQL injection.
Expected result: The API route at /api/products returns JSON with products from Neon Postgres. GET with ?q=search works. POST creates new records. Query results match the data in your Neon Console.
Generate the UI in V0 and Connect It to the API Routes
Generate the UI in V0 and Connect It to the API Routes
With your database and API routes in place, use V0 to generate the React components that display and interact with your PostgreSQL data. In V0's chat panel, describe the UI you want — reference the API route paths you created so V0 knows where to fetch data from. V0 generates React components using Tailwind CSS and shadcn/ui. When you reference a specific API endpoint in your prompt, V0 will include the correct fetch call and data mapping in the generated component. Review the preview to make sure the layout matches your expectations. For the product catalog example, V0 will generate a page with a search input, category filter buttons, and a product grid. The component will fetch from `/api/products` with the search and category parameters. Check that the component handles: - Loading state: skeleton cards or a spinner while fetching - Empty state: a message when no results match the filter - Error state: a user-friendly error message if the fetch fails - The correct data fields: your component should use the same field names your API route returns (`id`, `name`, `price`, `category`, `image_url`) If the V0-generated component uses slightly different field names or expects a different response structure, either regenerate with a more specific prompt or edit the component's data mapping code to match your actual API response. Once satisfied, push to GitHub using V0's Git panel to trigger a Vercel deployment. Because Vercel already has DATABASE_URL injected from the Marketplace setup, your deployment will immediately connect to the real Neon database without any additional configuration.
Build a product catalog page with a search input at the top, a row of category filter buttons (All, Electronics, Clothing, Home, Books), and a responsive grid of product cards. Each card shows the product image, name, category badge, and price in bold. Fetch products from /api/products with q and category query parameters. Show a loading skeleton grid while fetching and an 'No products found' empty state message.
Paste this in V0 chat
Pro tip: For your first V0 app with Neon, start by inserting a few test rows directly in the Neon Console SQL Editor before testing the frontend — this lets you verify the API route works before debugging the UI layer.
Expected result: Your V0-generated product catalog loads real PostgreSQL data from Neon. Search and category filtering works. The Vercel deployment is live and the Storage tab in Vercel shows database activity.
Use Neon Database Branching for Preview Deployments
Use Neon Database Branching for Preview Deployments
One of Neon's most powerful features for V0/Vercel workflows is database branching. Just like Git branches let you work on code changes without affecting the main branch, Neon database branches let each Vercel preview deployment have its own isolated copy of the database. This means you can safely test schema migrations, seed test data, and try out new features in pull request deployments without any risk to your production data. When Vercel Marketplace provisioned Neon, it configured this branching automatically. Every time you create a pull request on your GitHub repository and Vercel creates a preview deployment, Neon creates a new database branch forked from the main branch at that point in time. The preview deployment's DATABASE_URL points to this branch — completely isolated from production. To take advantage of this for schema changes: first run your new CREATE TABLE or ALTER TABLE statements on the Neon main branch in the Neon Console to update production. Then create a new branch in Neon manually (Neon Console → Branches → Create Branch) to test more experimental changes. Vercel's preview deployments will use their auto-created branches. To seed test data for previews, you can add a `seed.sql` file to your repository and run it against the preview branch's DATABASE_URL using the Neon CLI or a Vercel build hook. For simple apps, it is often easier to just insert test rows directly in the Neon Console for the specific branch you are testing. The combination of Vercel preview deployments and Neon database branching gives you a complete staging environment per pull request — the most robust testing workflow available for V0-built apps.
1// Example: Use transactions with Pool for multi-step operations2import { Pool } from '@neondatabase/serverless';34export async function POST(request: NextRequest) {5 const pool = new Pool({ connectionString: process.env.DATABASE_URL });67 try {8 const body = await request.json();9 const { userId, productId, quantity, totalPrice } = body;1011 // Transaction: create order AND update inventory atomically12 const client = await pool.connect();13 try {14 await client.query('BEGIN');1516 const { rows: [order] } = await client.query(17 `INSERT INTO orders (user_id, product_id, quantity, total_price)18 VALUES ($1, $2, $3, $4) RETURNING *`,19 [userId, productId, quantity, totalPrice]20 );2122 await client.query(23 `UPDATE products SET stock = stock - $1 WHERE id = $2`,24 [quantity, productId]25 );2627 await client.query('COMMIT');28 return NextResponse.json({ order }, { status: 201 });29 } catch (err) {30 await client.query('ROLLBACK');31 throw err;32 } finally {33 client.release();34 }35 } catch (error) {36 return NextResponse.json({ error: 'Transaction failed' }, { status: 500 });37 } finally {38 await pool.end();39 }40}Pro tip: Check your Neon Console → Branches after creating a GitHub pull request — you will see Vercel automatically created a new database branch for that PR's preview deployment. This is completely automatic with the Marketplace integration.
Expected result: Preview deployments on Vercel use isolated Neon database branches. The Neon Console shows separate branches for production and each active PR. Schema changes tested in preview do not affect production data.
Common use cases
User Data and Profile Storage
A SaaS app built with V0 needs to store user profiles, preferences, and account data. Neon Postgres stores all user records in a structured schema with proper data types and constraints. The Next.js API routes handle CRUD operations securely server-side.
Create a user profile settings page with fields for display name, email, bio, and avatar URL. Include a save button that POSTs to /api/users/profile. Show a success toast on save. Use a clean form layout with Tailwind styling and shadcn form components.
Copy this prompt to try it in V0
Product Catalog with Search and Filtering
An e-commerce app stores its product catalog in Neon Postgres with full-text search using PostgreSQL's native tsvector. V0 generates a product grid UI with a search input and category filters, and an API route queries the database with the user's search terms.
Build a product catalog page with a search input, category filter buttons, a grid of product cards showing image, name, price, and an Add to Cart button, and a total results count. The grid should fetch from /api/products with q and category query parameters.
Copy this prompt to try it in V0
Analytics Dashboard with Aggregated Metrics
A dashboard app queries Neon Postgres with aggregation queries (COUNT, SUM, GROUP BY) to display business metrics. V0 generates the chart and KPI card components, and an API route runs the SQL aggregation queries and returns pre-computed data.
Create an analytics dashboard with a date range picker at the top, four KPI cards showing total users, active users, total revenue, and average session duration, and a line chart showing daily signups over the selected period. Fetch all data from /api/analytics/overview with startDate and endDate query params.
Copy this prompt to try it in V0
Troubleshooting
API route returns 'password authentication failed for user' or 'connection refused' error
Cause: The DATABASE_URL environment variable is not available in the current environment. This commonly happens when testing locally before running `vercel env pull` to download the injected variables, or when a new deployment was not triggered after the Marketplace setup.
Solution: Run `vercel env pull .env.local` in your project root (requires Vercel CLI: `npm i -g vercel`) to download the Marketplace-provisioned DATABASE_URL to your local .env.local file. If deploying on Vercel, go to the Deployments tab, find the deployment with the error, and trigger a Redeploy to ensure it picks up the current environment variables.
neon() tagged template conditional clauses throw TypeScript errors or fail at runtime
Cause: Conditional SQL fragments in neon() tagged templates (like `${condition ? sql\`WHERE ...\` : sql\`\`}`) require importing the `sql` helper function specifically for template fragments. Without it, TypeScript cannot type the conditional correctly.
Solution: Import both `neon` and `sql` from @neondatabase/serverless. Use the `sql` tagged template for conditional fragments to ensure correct parameterization.
1import { neon, sql } from '@neondatabase/serverless';2const db = neon(process.env.DATABASE_URL!);34// Correct pattern for conditional WHERE clauses5const rows = await db`6 SELECT * FROM products7 ${category ? sql`WHERE category = ${category}` : sql``}8 LIMIT 509`;Queries work in development but return stale data in the Vercel production deployment
Cause: Next.js caches fetch responses by default in the App Router. If your API route uses React Server Components with fetch, or if you used `next: { revalidate: N }` in a fetch call, the data may be served from Next.js's cache.
Solution: To disable caching for database queries that need real-time data, add `export const dynamic = 'force-dynamic'` to your API route file. For routes that can tolerate some staleness, use `next: { revalidate: 60 }` to revalidate every 60 seconds.
1// app/api/products/route.ts2export const dynamic = 'force-dynamic'; // Always fetch fresh data3// OR: export const revalidate = 60; // Revalidate every 60 secondsNeon database shows as 'suspended' and queries fail with a timeout on the first request
Cause: Neon's free tier databases scale to zero after 5 minutes of inactivity. The first query after a period of inactivity triggers a cold start that can take 1-3 seconds while Neon resumes the compute.
Solution: This is expected behavior on Neon's free tier. For production apps with latency requirements, upgrade to a Neon paid plan that disables scale-to-zero. For development and low-traffic apps, the 1-3 second cold start is acceptable. You can also implement a warmup endpoint that pings the database periodically.
Best practices
- Always use the neon() tagged template literal for parameterized queries — never concatenate user input directly into SQL strings to prevent SQL injection.
- Use `Pool` from @neondatabase/serverless for multi-statement transactions, and always call `client.release()` in a finally block to return the connection to the pool.
- Add `export const dynamic = 'force-dynamic'` to API routes that query real-time data — this prevents Next.js from caching database responses.
- Run `vercel env pull .env.local` when starting local development to get the exact DATABASE_URL that Vercel provisioned — this ensures local and production environments use the same Neon project.
- Use Neon's database branching in combination with Vercel preview deployments to test schema migrations safely in isolated environments before merging to production.
- Add `LIMIT` clauses to all SELECT queries — without them, a query could accidentally return thousands of rows and exhaust your Neon storage or slow down your serverless function.
- Use `RETURNING *` in INSERT and UPDATE statements to get the created/modified record back in the same query, avoiding a separate SELECT round-trip.
Alternatives
MongoDB Atlas also has a Vercel integration and suits unstructured or rapidly evolving data schemas better than PostgreSQL's fixed schema approach.
Firebase Firestore is fully managed by Google with real-time sync built in, making it better for apps that need live data updates without building WebSocket infrastructure.
Airtable provides a spreadsheet-like interface for non-technical team members to manage data, making it better for content-driven apps where editors need direct database access.
Oracle Database is the right choice when connecting to existing enterprise Oracle infrastructure, but Neon Postgres is significantly easier to set up for new V0 projects.
Frequently asked questions
Is Neon Postgres the same as standard PostgreSQL?
Yes, Neon runs standard PostgreSQL (version 15 and 16 as of 2026) and is fully compatible with any PostgreSQL client, ORM, or query builder. The `@neondatabase/serverless` package is an optimization for serverless environments, but you can also use standard pg or Drizzle ORM with Neon. All standard PostgreSQL features — extensions, full-text search, JSON types, triggers — work identically.
Do I need a separate Neon account when using Vercel Marketplace?
No. The Vercel Marketplace integration creates a Neon account on your behalf and links it to your Vercel account. You can access the Neon Console directly from your Vercel project's Storage tab without creating a separate account or managing separate credentials.
Can I use an ORM like Drizzle or Prisma with Neon on Vercel?
Yes. Both Drizzle ORM and Prisma work with Neon. Drizzle is particularly popular with Next.js and Neon because of its TypeScript-first approach and lightweight runtime. Use `drizzle-orm` with `@neondatabase/serverless` as the driver. Prisma works with Neon's DATABASE_URL using the standard Prisma Postgres adapter — use Prisma Accelerate for optimal serverless connection pooling.
What is the difference between DATABASE_URL and DATABASE_URL_UNPOOLED?
DATABASE_URL connects to Neon via PgBouncer connection pooling, which is optimized for serverless functions that open many short-lived connections. DATABASE_URL_UNPOOLED connects directly to the Neon compute without pooling. Use DATABASE_URL (pooled) for application queries in serverless functions. Use DATABASE_URL_UNPOOLED for database migrations and schema changes, as PgBouncer does not support transaction-mode operations needed for migrations.
How do I run database migrations for my Neon database?
For simple cases, run SQL directly in the Neon Console SQL Editor. For managed migrations, use Drizzle Kit (`drizzle-kit push` for development, `drizzle-kit migrate` for production) or Prisma Migrate. Always use DATABASE_URL_UNPOOLED for running migrations, as the unpooled connection supports the session-mode required by migration tools.
Is the free Neon tier sufficient for a production V0 app?
The free tier (0.5 GB storage, scale-to-zero compute) is good for development and low-traffic production apps. For production apps with consistent traffic, the scale-to-zero cold start (1-3 seconds after 5 minutes of inactivity) is the main limitation. Neon's Launch plan ($19/month) disables scale-to-zero and is the recommended upgrade for production apps with latency requirements.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation