Connect Next.js to Xata
Learn how to connect your Next.js application to Xata's PostgreSQL platform. Get started with Next.js and PostgreSQL for scalable web applications.
Prerequisites
- Xata account and project setup
- Node.js 18+ installed
- Basic knowledge of React and Next.js
Setup Xata Database
First, set up your Xata database with the common e-commerce dataset:
- Create a project and branch in the Xata console
- Navigate to the Queries tab in your branch
- Run the following SQL commands to create the initial schema:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
price NUMERIC(7,2) NOT NULL,
rating INTEGER
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE order_items (
order_id INTEGER REFERENCES orders(id),
product_id INTEGER REFERENCES products(id),
qty INTEGER NOT NULL,
PRIMARY KEY (order_id, product_id)
);
Create Next.js Project
Create a new Next.js project with TypeScript:
npx create-next-app@latest my-xata-app --typescript --tailwind --eslint
cd my-xata-app
Initialize Xata Project
Initialize your Xata project configuration:
xata init
This will create a .xata
directory with your project configuration.
Store Your Credentials
Create a .env.local
file in your project root to store your Xata connection string:
# .env.local
DATABASE_URL="postgresql://username:password@host:port/database"
Get your connection string from the Xata console or CLI:
xata branch url
Important: Never commit your .env.local
file to version control. Add it to your .gitignore
file.
Install Dependencies
Install the PostgreSQL client:
npm install postgres
npm install -D @types/pg
Configure Database Connection
Create a database configuration file:
// lib/db.ts
import postgres from 'postgres';
const connectionString = process.env.DATABASE_URL;
if (!connectionString) {
throw new Error('DATABASE_URL environment variable is required');
}
export const sql = postgres(connectionString);
Create API Routes
Create API routes for your products:
// app/api/products/route.ts
import { NextResponse } from 'next/server';
import { sql } from '@/lib/db';
export async function GET() {
try {
const products = await sql`SELECT * FROM products`;
return NextResponse.json(products);
} catch (error) {
return NextResponse.json({ error: 'Failed to fetch products' }, { status: 500 });
}
}
export async function POST(request: Request) {
try {
const body = await request.json();
const [newProduct] = await sql`
INSERT INTO products (name, price, rating)
VALUES (${body.name}, ${body.price}, ${body.rating})
RETURNING *
`;
return NextResponse.json(newProduct, { status: 201 });
} catch (error) {
return NextResponse.json({ error: 'Failed to create product' }, { status: 500 });
}
}
// app/api/products/[id]/route.ts
import { NextResponse } from 'next/server';
import { sql } from '@/lib/db';
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
try {
const [product] = await sql`SELECT * FROM products WHERE id = ${params.id}`;
if (!product) {
return NextResponse.json({ error: 'Product not found' }, { status: 404 });
}
return NextResponse.json(product);
} catch (error) {
return NextResponse.json({ error: 'Failed to fetch product' }, { status: 500 });
}
}
Create Components
Create a products list component:
// components/ProductsList.tsx
'use client';
import { useState, useEffect } from 'react';
import type { Product } from '@/lib/schema';
export default function ProductsList() {
const [products, setProducts] = useState<Product[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/products')
.then(res => res.json())
.then(data => {
setProducts(data);
setLoading(false);
})
.catch(error => {
console.error('Error fetching products:', error);
setLoading(false);
});
}, []);
if (loading) return <div>Loading products...</div>;
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{products.map((product) => (
<div key={product.id} className="border rounded-lg p-4">
<h3 className="text-lg font-semibold">{product.name}</h3>
<p className="text-gray-600">${product.price}</p>
{product.rating && (
<div className="flex items-center mt-2">
<span className="text-yellow-500">★</span>
<span className="ml-1">{product.rating}/5</span>
</div>
)}
</div>
))}
</div>
);
}
Update Main Page
Update your main page to display products:
// app/page.tsx
import ProductsList from '@/components/ProductsList';
export default function Home() {
return (
<main className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-8">Xata E-commerce Store</h1>
<ProductsList />
</main>
);
}
Run the Application
Start your development server:
npm run dev
Visit http://localhost:3000
to see your application.
Next Steps
- Explore Xata branching for development workflows
- Learn about schema changes with zero downtime
- Join our Discord community for help and support