neon-serverless-postgres
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNeon Serverless Postgres Skill
Neon Serverless Postgres 技能
progressive_disclosure: entry_point: summary: "Serverless Postgres with autoscaling, branching, and instant database provisioning" when_to_use: - "When needing serverless Postgres" - "When building edge and serverless apps" - "When implementing database branching for dev/staging" - "When using Drizzle, Prisma, or raw SQL" quick_start: - "Create project on Neon console" - "Get connection string" - "Connect with Drizzle/Prisma/pg" - "Deploy with Vercel/Netlify" token_estimate: entry: 75-90 full: 3800-4800
progressive_disclosure: entry_point: summary: "支持自动扩缩容、分支和即时数据库预置的Serverless Postgres" when_to_use: - "需要使用serverless Postgres时" - "构建边缘和serverless应用时" - "为开发/预发环境实现数据库分支时" - "使用Drizzle、Prisma或原生SQL时" quick_start: - "在Neon控制台创建项目" - "获取连接字符串" - "使用Drizzle/Prisma/pg连接" - "通过Vercel/Netlify部署" token_estimate: entry: 75-90 full: 3800-4800
Core Concepts
核心概念
Neon Architecture
Neon 架构
- Projects: Top-level container for databases and branches
- Databases: Postgres databases within a project
- Branches: Git-like database copies for development
- Compute: Autoscaling Postgres instances
- Storage: Separated from compute for instant branching
- 项目:数据库和分支的顶层容器
- 数据库:项目内的Postgres数据库
- 分支:类似Git的开发用数据库副本
- 计算资源:自动扩缩容的Postgres实例
- 存储:与计算资源分离,支持即时分支
Key Features
核心特性
- Serverless: Pay-per-use, scales to zero
- Branching: Instant database copies from any point in time
- Autoscaling: Compute scales based on load
- Instant Provisioning: Databases ready in seconds
- Connection Pooling: Built-in PgBouncer support
- Serverless:按使用付费,空闲时可缩容到0
- 分支能力:可从任意时间点即时创建数据库副本
- 自动扩缩容:计算资源根据负载动态调整
- 即时预置:数秒内即可完成数据库准备
- 连接池:内置PgBouncer支持
Connection Strings
连接字符串
Standard Connection
标准连接
bash
undefinedbash
undefinedDirect connection (for migrations, admin tasks)
Direct connection (for migrations, admin tasks)
DATABASE_URL="postgresql://user:password@ep-xxx.region.aws.neon.tech/dbname"
DATABASE_URL="postgresql://user:password@ep-xxx.region.aws.neon.tech/dbname"
Pooled connection (for application queries)
Pooled connection (for application queries)
DATABASE_URL="postgresql://user:password@ep-xxx.region.aws.neon.tech/dbname?sslmode=require"
undefinedDATABASE_URL="postgresql://user:password@ep-xxx.region.aws.neon.tech/dbname?sslmode=require"
undefinedConnection Pooling
连接池配置
bash
undefinedbash
undefinedPgBouncer pooled connection (recommended for serverless)
PgBouncer pooled connection (recommended for serverless)
DATABASE_URL="postgresql://user:password@ep-xxx-pooler.region.aws.neon.tech/dbname?sslmode=require"
DATABASE_URL="postgresql://user:password@ep-xxx-pooler.region.aws.neon.tech/dbname?sslmode=require"
Direct connection for migrations
Direct connection for migrations
DIRECT_URL="postgresql://user:password@ep-xxx.region.aws.neon.tech/dbname"
undefinedDIRECT_URL="postgresql://user:password@ep-xxx.region.aws.neon.tech/dbname"
undefinedDrizzle ORM Integration
Drizzle ORM 集成
Setup
配置
typescript
// drizzle.config.ts
import type { Config } from "drizzle-kit";
export default {
schema: "./src/db/schema.ts",
out: "./drizzle",
driver: "pg",
dbCredentials: {
connectionString: process.env.DATABASE_URL!,
},
} satisfies Config;
// src/db/index.ts
import { drizzle } from "drizzle-orm/neon-http";
import { neon } from "@neondatabase/serverless";
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql);typescript
// drizzle.config.ts
import type { Config } from "drizzle-kit";
export default {
schema: "./src/db/schema.ts",
out: "./drizzle",
driver: "pg",
dbCredentials: {
connectionString: process.env.DATABASE_URL!,
},
} satisfies Config;
// src/db/index.ts
import { drizzle } from "drizzle-orm/neon-http";
import { neon } from "@neondatabase/serverless";
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql);Schema Definition
表结构定义
typescript
// src/db/schema.ts
import { pgTable, serial, text, timestamp, varchar } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: serial("id").primaryKey(),
name: varchar("name", { length: 255 }).notNull(),
email: varchar("email", { length: 255 }).notNull().unique(),
createdAt: timestamp("created_at").defaultNow(),
});
export const posts = pgTable("posts", {
id: serial("id").primaryKey(),
title: text("title").notNull(),
content: text("content"),
userId: serial("user_id").references(() => users.id),
createdAt: timestamp("created_at").defaultNow(),
});typescript
// src/db/schema.ts
import { pgTable, serial, text, timestamp, varchar } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: serial("id").primaryKey(),
name: varchar("name", { length: 255 }).notNull(),
email: varchar("email", { length: 255 }).notNull().unique(),
createdAt: timestamp("created_at").defaultNow(),
});
export const posts = pgTable("posts", {
id: serial("id").primaryKey(),
title: text("title").notNull(),
content: text("content"),
userId: serial("user_id").references(() => users.id),
createdAt: timestamp("created_at").defaultNow(),
});Queries
数据查询
typescript
import { db } from "./db";
import { users, posts } from "./db/schema";
import { eq } from "drizzle-orm";
// Insert
const newUser = await db.insert(users).values({
name: "John Doe",
email: "john@example.com",
}).returning();
// Query
const allUsers = await db.select().from(users);
// Join
const userPosts = await db
.select()
.from(posts)
.leftJoin(users, eq(posts.userId, users.id));
// Update
await db.update(users)
.set({ name: "Jane Doe" })
.where(eq(users.id, 1));typescript
import { db } from "./db";
import { users, posts } from "./db/schema";
import { eq } from "drizzle-orm";
// Insert
const newUser = await db.insert(users).values({
name: "John Doe",
email: "john@example.com",
}).returning();
// Query
const allUsers = await db.select().from(users);
// Join
const userPosts = await db
.select()
.from(posts)
.leftJoin(users, eq(posts.userId, users.id));
// Update
await db.update(users)
.set({ name: "Jane Doe" })
.where(eq(users.id, 1));Migrations
数据迁移
bash
undefinedbash
undefinedGenerate migration
Generate migration
npx drizzle-kit generate:pg
npx drizzle-kit generate:pg
Run migration (use direct connection)
Run migration (use direct connection)
npx drizzle-kit push:pg
npx drizzle-kit push:pg
Or use custom script
Or use custom script
src/db/migrate.ts
src/db/migrate.ts
import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import postgres from "postgres";
const sql = postgres(process.env.DIRECT_URL!, { max: 1 });
const db = drizzle(sql);
await migrate(db, { migrationsFolder: "./drizzle" });
await sql.end();
undefinedimport { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import postgres from "postgres";
const sql = postgres(process.env.DIRECT_URL!, { max: 1 });
const db = drizzle(sql);
await migrate(db, { migrationsFolder: "./drizzle" });
await sql.end();
undefinedPrisma Integration
Prisma 集成
Setup
配置
prisma
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL") // For migrations
}
model User {
id Int @id @default(autoincrement())
name String
email String @unique
posts Post[]
createdAt DateTime @default(now())
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
userId Int
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
}prisma
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL") // For migrations
}
model User {
id Int @id @default(autoincrement())
name String
email String @unique
posts Post[]
createdAt DateTime @default(now())
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
userId Int
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
}Client Usage
客户端使用
typescript
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
// Create
const user = await prisma.user.create({
data: {
name: "John Doe",
email: "john@example.com",
},
});
// Query with relations
const userWithPosts = await prisma.user.findUnique({
where: { id: 1 },
include: { posts: true },
});
// Transaction
await prisma.$transaction([
prisma.user.create({ data: { name: "User 1", email: "u1@example.com" } }),
prisma.user.create({ data: { name: "User 2", email: "u2@example.com" } }),
]);typescript
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
// Create
const user = await prisma.user.create({
data: {
name: "John Doe",
email: "john@example.com",
},
});
// Query with relations
const userWithPosts = await prisma.user.findUnique({
where: { id: 1 },
include: { posts: true },
});
// Transaction
await prisma.$transaction([
prisma.user.create({ data: { name: "User 1", email: "u1@example.com" } }),
prisma.user.create({ data: { name: "User 2", email: "u2@example.com" } }),
]);Migrations
数据迁移
bash
undefinedbash
undefinedCreate migration
Create migration
npx prisma migrate dev --name init
npx prisma migrate dev --name init
Deploy to production (uses DIRECT_URL)
Deploy to production (uses DIRECT_URL)
npx prisma migrate deploy
npx prisma migrate deploy
Generate client
Generate client
npx prisma generate
undefinednpx prisma generate
undefinedNode-Postgres (pg) Integration
Node-Postgres (pg) 集成
Direct Connection
直接连接
typescript
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: { rejectUnauthorized: false },
});
// Query
const result = await pool.query("SELECT * FROM users WHERE email = $1", [
"john@example.com",
]);
// Transaction
const client = await pool.connect();
try {
await client.query("BEGIN");
await client.query("INSERT INTO users (name, email) VALUES ($1, $2)", [
"John",
"john@example.com",
]);
await client.query("COMMIT");
} catch (e) {
await client.query("ROLLBACK");
throw e;
} finally {
client.release();
}typescript
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: { rejectUnauthorized: false },
});
// Query
const result = await pool.query("SELECT * FROM users WHERE email = $1", [
"john@example.com",
]);
// Transaction
const client = await pool.connect();
try {
await client.query("BEGIN");
await client.query("INSERT INTO users (name, email) VALUES ($1, $2)", [
"John",
"john@example.com",
]);
await client.query("COMMIT");
} catch (e) {
await client.query("ROLLBACK");
throw e;
} finally {
client.release();
}Serverless Driver
Serverless 驱动
typescript
import { neon, neonConfig } from "@neondatabase/serverless";
// Configure for edge runtime
neonConfig.fetchConnectionCache = true;
const sql = neon(process.env.DATABASE_URL!);
// Execute query
const result = await sql`SELECT * FROM users WHERE email = ${email}`;
// Transactions
const [user] = await sql.transaction([
sql`INSERT INTO users (name, email) VALUES (${name}, ${email}) RETURNING *`,
sql`INSERT INTO audit_log (action) VALUES ('user_created')`,
]);typescript
import { neon, neonConfig } from "@neondatabase/serverless";
// Configure for edge runtime
neonConfig.fetchConnectionCache = true;
const sql = neon(process.env.DATABASE_URL!);
// Execute query
const result = await sql`SELECT * FROM users WHERE email = ${email}`;
// Transactions
const [user] = await sql.transaction([
sql`INSERT INTO users (name, email) VALUES (${name}, ${email}) RETURNING *`,
sql`INSERT INTO audit_log (action) VALUES ('user_created')`,
]);Database Branching
数据库分支
Branch Types
分支类型
- Main: Production branch
- Development: Feature development
- Preview: PR/deployment previews
- Testing: QA and testing environments
- Main:生产环境分支
- Development:功能开发分支
- Preview:PR/部署预览分支
- Testing:QA和测试环境分支
Creating Branches
创建分支
bash
undefinedbash
undefinedVia CLI
Via CLI
neonctl branches create --name dev --parent main
neonctl branches create --name dev --parent main
Via API
Via API
curl -X POST https://console.neon.tech/api/v2/projects/{project_id}/branches
-H "Authorization: Bearer $NEON_API_KEY"
-d '{"name": "dev", "parent_id": "main"}'
-H "Authorization: Bearer $NEON_API_KEY"
-d '{"name": "dev", "parent_id": "main"}'
curl -X POST https://console.neon.tech/api/v2/projects/{project_id}/branches
-H "Authorization: Bearer $NEON_API_KEY"
-d '{"name": "dev", "parent_id": "main"}'
-H "Authorization: Bearer $NEON_API_KEY"
-d '{"name": "dev", "parent_id": "main"}'
Via Console
Via Console
Navigate to project → Branches → Create branch
Navigate to project → Branches → Create branch
undefinedundefinedBranch Workflows
分支工作流
Feature Development
功能开发
bash
undefinedbash
undefined1. Create feature branch
1. Create feature branch
neonctl branches create --name feature/user-auth --parent dev
neonctl branches create --name feature/user-auth --parent dev
2. Get connection string
2. Get connection string
neonctl connection-string feature/user-auth
neonctl connection-string feature/user-auth
3. Update .env.local
3. Update .env.local
DATABASE_URL="postgresql://...feature-user-auth..."
DATABASE_URL="postgresql://...feature-user-auth..."
4. Run migrations
4. Run migrations
npm run migrate
npm run migrate
5. Develop and test
5. Develop and test
6. Merge changes (via schema migration)
6. Merge changes (via schema migration)
7. Delete branch
7. Delete branch
neonctl branches delete feature/user-auth
undefinedneonctl branches delete feature/user-auth
undefinedPreview Deployments
预览部署
typescript
// vercel.json
{
"env": {
"DATABASE_URL": "@database-url-main"
},
"build": {
"env": {
"DATABASE_URL": "@database-url-preview"
}
}
}
// Create preview branch on deploy
// .github/workflows/preview.yml
- name: Create Neon Branch
run: |
BRANCH_NAME="preview-${{ github.event.number }}"
neonctl branches create --name $BRANCH_NAME --parent main
DATABASE_URL=$(neonctl connection-string $BRANCH_NAME)
echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENVtypescript
// vercel.json
{
"env": {
"DATABASE_URL": "@database-url-main"
},
"build": {
"env": {
"DATABASE_URL": "@database-url-preview"
}
}
}
// Create preview branch on deploy
// .github/workflows/preview.yml
- name: Create Neon Branch
run: |
BRANCH_NAME="preview-${{ github.event.number }}"
neonctl branches create --name $BRANCH_NAME --parent main
DATABASE_URL=$(neonctl connection-string $BRANCH_NAME)
echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENVPoint-in-Time Recovery
时间点恢复
bash
undefinedbash
undefinedCreate branch from specific timestamp
Create branch from specific timestamp
neonctl branches create --name recovery
--parent main
--timestamp "2024-01-15T10:30:00Z"
--parent main
--timestamp "2024-01-15T10:30:00Z"
neonctl branches create --name recovery
--parent main
--timestamp "2024-01-15T10:30:00Z"
--parent main
--timestamp "2024-01-15T10:30:00Z"
Restore from branch
Restore from branch
neonctl branches reset main --from recovery
undefinedneonctl branches reset main --from recovery
undefinedVercel Integration
Vercel 集成
Automatic Setup
自动配置
bash
undefinedbash
undefinedInstall Vercel CLI
Install Vercel CLI
npm i -g vercel
npm i -g vercel
Link project
Link project
vercel link
vercel link
Add Neon integration
Add Neon integration
vercel integration add neon
vercel integration add neon
Vercel automatically:
Vercel automatically:
- Creates main branch connection
- Creates main branch connection
- Creates preview branch per PR
- Creates preview branch per PR
- Sets DATABASE_URL environment variable
- Sets DATABASE_URL environment variable
undefinedundefinedManual Configuration
手动配置
bash
undefinedbash
undefinedAdd to Vercel project settings
Add to Vercel project settings
vercel env add DATABASE_URL
vercel env add DATABASE_URL
For preview branches
For preview branches
vercel env add DATABASE_URL preview
vercel env add DATABASE_URL preview
For production
For production
vercel env add DATABASE_URL production
undefinedvercel env add DATABASE_URL production
undefinedNext.js Integration
Next.js 集成
typescript
// app/api/users/route.ts
import { neon } from "@neondatabase/serverless";
export const runtime = "edge";
export async function GET() {
const sql = neon(process.env.DATABASE_URL!);
const users = await sql`SELECT * FROM users`;
return Response.json(users);
}
// app/api/users/[id]/route.ts
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
const sql = neon(process.env.DATABASE_URL!);
const [user] = await sql`SELECT * FROM users WHERE id = ${params.id}`;
if (!user) {
return new Response("Not found", { status: 404 });
}
return Response.json(user);
}typescript
// app/api/users/route.ts
import { neon } from "@neondatabase/serverless";
export const runtime = "edge";
export async function GET() {
const sql = neon(process.env.DATABASE_URL!);
const users = await sql`SELECT * FROM users`;
return Response.json(users);
}
// app/api/users/[id]/route.ts
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
const sql = neon(process.env.DATABASE_URL!);
const [user] = await sql`SELECT * FROM users WHERE id = ${params.id}`;
if (!user) {
return new Response("Not found", { status: 404 });
}
return Response.json(user);
}Connection Pooling
连接池
PgBouncer Pooling
PgBouncer 连接池
typescript
// Use pooled connection for queries
const pooledDb = drizzle(neon(process.env.DATABASE_URL!));
// Use direct connection for migrations
const directDb = drizzle(neon(process.env.DIRECT_URL!));
// package.json scripts
{
"scripts": {
"migrate": "DATABASE_URL=$DIRECT_URL drizzle-kit push:pg",
"dev": "next dev"
}
}typescript
// Use pooled connection for queries
const pooledDb = drizzle(neon(process.env.DATABASE_URL!));
// Use direct connection for migrations
const directDb = drizzle(neon(process.env.DIRECT_URL!));
// package.json scripts
{
"scripts": {
"migrate": "DATABASE_URL=$DIRECT_URL drizzle-kit push:pg",
"dev": "next dev"
}
}Connection Limits
连接数限制
typescript
// Configure pool size
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20, // Max connections
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
// For serverless, use Neon's serverless driver
import { neon } from "@neondatabase/serverless";
// Automatically handles connection poolingtypescript
// Configure pool size
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20, // Max connections
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
// For serverless, use Neon's serverless driver
import { neon } from "@neondatabase/serverless";
// Automatically handles connection poolingAutoscaling and Compute
自动扩缩容与计算资源
Compute Units
计算单元
yaml
undefinedyaml
undefinedFree Tier
Free Tier
- 0.25 Compute Units (CU)
- Scales to zero when idle
- Shared compute
- 0.25 Compute Units (CU)
- Scales to zero when idle
- Shared compute
Pro Tier
Pro Tier
- 0.25 - 4 CU autoscaling
- Configurable min/max
- Dedicated compute
undefined- 0.25 - 4 CU autoscaling
- Configurable min/max
- Dedicated compute
undefinedConfiguration
配置方式
bash
undefinedbash
undefinedVia CLI
Via CLI
neonctl set-compute --min 0.25 --max 2 --branch main
neonctl set-compute --min 0.25 --max 2 --branch main
Via API
Via API
curl -X PATCH https://console.neon.tech/api/v2/projects/{id}/branches/{branch_id}
-d '{"compute": {"min_cu": 0.25, "max_cu": 2}}'
-d '{"compute": {"min_cu": 0.25, "max_cu": 2}}'
undefinedcurl -X PATCH https://console.neon.tech/api/v2/projects/{id}/branches/{branch_id}
-d '{"compute": {"min_cu": 0.25, "max_cu": 2}}'
-d '{"compute": {"min_cu": 0.25, "max_cu": 2}}'
undefinedAutoscaling Strategy
自动扩缩容策略
typescript
// Development: Scale to zero
// min: 0.25 CU, max: 1 CU
// Staging: Minimal baseline
// min: 0.5 CU, max: 2 CU
// Production: Always-on baseline
// min: 1 CU, max: 4 CU
// Configure per branch
const computeConfig = {
dev: { min: 0.25, max: 1 },
staging: { min: 0.5, max: 2 },
main: { min: 1, max: 4 },
};typescript
// Development: Scale to zero
// min: 0.25 CU, max: 1 CU
// Staging: Minimal baseline
// min: 0.5 CU, max: 2 CU
// Production: Always-on baseline
// min: 1 CU, max: 4 CU
// Configure per branch
const computeConfig = {
dev: { min: 0.25, max: 1 },
staging: { min: 0.5, max: 2 },
main: { min: 1, max: 4 },
};Read Replicas
只读副本
Setup
配置
bash
undefinedbash
undefinedCreate read replica
Create read replica
neonctl read-replica create --branch main --region us-east-1
neonctl read-replica create --branch main --region us-east-1
Get connection string
Get connection string
neonctl connection-string --replica
undefinedneonctl connection-string --replica
undefinedUsage Pattern
使用方式
typescript
// Write to primary
const writeDb = drizzle(neon(process.env.DATABASE_URL!));
// Read from replica
const readDb = drizzle(neon(process.env.DATABASE_URL_REPLICA!));
// Application logic
async function getUser(id: number) {
return await readDb.select().from(users).where(eq(users.id, id));
}
async function updateUser(id: number, data: any) {
return await writeDb.update(users).set(data).where(eq(users.id, id));
}
// Load balancing
const replicas = [
process.env.DATABASE_URL_REPLICA_1!,
process.env.DATABASE_URL_REPLICA_2!,
];
function getReadConnection() {
const url = replicas[Math.floor(Math.random() * replicas.length)];
return drizzle(neon(url));
}typescript
// Write to primary
const writeDb = drizzle(neon(process.env.DATABASE_URL!));
// Read from replica
const readDb = drizzle(neon(process.env.DATABASE_URL_REPLICA!));
// Application logic
async function getUser(id: number) {
return await readDb.select().from(users).where(eq(users.id, id));
}
async function updateUser(id: number, data: any) {
return await writeDb.update(users).set(data).where(eq(users.id, id));
}
// Load balancing
const replicas = [
process.env.DATABASE_URL_REPLICA_1!,
process.env.DATABASE_URL_REPLICA_2!,
];
function getReadConnection() {
const url = replicas[Math.floor(Math.random() * replicas.length)];
return drizzle(neon(url));
}CLI Usage
CLI 使用
Installation
安装
bash
npm install -g neonctlbash
npm install -g neonctlOr use npx
Or use npx
npx neonctl --help
undefinednpx neonctl --help
undefinedCommon Commands
常用命令
bash
undefinedbash
undefinedAuthentication
Authentication
neonctl auth
neonctl auth
List projects
List projects
neonctl projects list
neonctl projects list
Create project
Create project
neonctl projects create --name my-app
neonctl projects create --name my-app
List branches
List branches
neonctl branches list
neonctl branches list
Create branch
Create branch
neonctl branches create --name dev --parent main
neonctl branches create --name dev --parent main
Get connection string
Get connection string
neonctl connection-string main
neonctl connection-string main
Database operations
Database operations
neonctl databases create --name analytics
neonctl databases list
neonctl databases create --name analytics
neonctl databases list
Compute settings
Compute settings
neonctl set-compute --min 0.5 --max 2
neonctl set-compute --min 0.5 --max 2
Delete branch
Delete branch
neonctl branches delete dev
undefinedneonctl branches delete dev
undefinedMigration Strategies
迁移策略
Drizzle Migrations
Drizzle 迁移
typescript
// drizzle/migrate.ts
import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import postgres from "postgres";
const runMigrations = async () => {
const connection = postgres(process.env.DIRECT_URL!, { max: 1 });
const db = drizzle(connection);
console.log("Running migrations...");
await migrate(db, { migrationsFolder: "./drizzle" });
console.log("Migrations complete!");
await connection.end();
};
runMigrations();typescript
// drizzle/migrate.ts
import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import postgres from "postgres";
const runMigrations = async () => {
const connection = postgres(process.env.DIRECT_URL!, { max: 1 });
const db = drizzle(connection);
console.log("Running migrations...");
await migrate(db, { migrationsFolder: "./drizzle" });
console.log("Migrations complete!");
await connection.end();
};
runMigrations();Prisma Migrations
Prisma 迁移
bash
undefinedbash
undefinedDevelopment
Development
npx prisma migrate dev --name add_users_table
npx prisma migrate dev --name add_users_table
Production (uses DIRECT_URL)
Production (uses DIRECT_URL)
npx prisma migrate deploy
npx prisma migrate deploy
Reset database (dev only)
Reset database (dev only)
npx prisma migrate reset
undefinednpx prisma migrate reset
undefinedZero-Downtime Migrations
零停机迁移
sql
-- 1. Add new column (nullable)
ALTER TABLE users ADD COLUMN new_email VARCHAR(255);
-- 2. Backfill data
UPDATE users SET new_email = email;
-- 3. Make non-nullable (after verification)
ALTER TABLE users ALTER COLUMN new_email SET NOT NULL;
-- 4. Drop old column
ALTER TABLE users DROP COLUMN email;
-- 5. Rename column
ALTER TABLE users RENAME COLUMN new_email TO email;sql
-- 1. Add new column (nullable)
ALTER TABLE users ADD COLUMN new_email VARCHAR(255);
-- 2. Backfill data
UPDATE users SET new_email = email;
-- 3. Make non-nullable (after verification)
ALTER TABLE users ALTER COLUMN new_email SET NOT NULL;
-- 4. Drop old column
ALTER TABLE users DROP COLUMN email;
-- 5. Rename column
ALTER TABLE users RENAME COLUMN new_email TO email;Branch-Based Migrations
基于分支的迁移
bash
undefinedbash
undefined1. Create migration branch
1. Create migration branch
neonctl branches create --name migration/add-index --parent main
neonctl branches create --name migration/add-index --parent main
2. Test migration on branch
2. Test migration on branch
DATABASE_URL=$(neonctl connection-string migration/add-index)
npm run migrate
npm run migrate
DATABASE_URL=$(neonctl connection-string migration/add-index)
npm run migrate
npm run migrate
3. Verify on branch
3. Verify on branch
DATABASE_URL=$(neonctl connection-string migration/add-index)
npm run test
npm run test
DATABASE_URL=$(neonctl connection-string migration/add-index)
npm run test
npm run test
4. Apply to main
4. Apply to main
npm run migrate:production
npm run migrate:production
5. Delete migration branch
5. Delete migration branch
neonctl branches delete migration/add-index
undefinedneonctl branches delete migration/add-index
undefinedBest Practices
最佳实践
Serverless Optimization
Serverless 优化
typescript
// ✅ Use Neon serverless driver for edge
import { neon } from "@neondatabase/serverless";
const sql = neon(process.env.DATABASE_URL!);
// ✅ Enable connection caching
import { neonConfig } from "@neondatabase/serverless";
neonConfig.fetchConnectionCache = true;
// ✅ Use pooled connections
const pooledUrl = process.env.DATABASE_URL; // -pooler endpoint
// ❌ Don't use standard pg in edge runtime
// import { Pool } from "pg"; // Won't work in edgetypescript
// ✅ Use Neon serverless driver for edge
import { neon } from "@neondatabase/serverless";
const sql = neon(process.env.DATABASE_URL!);
// ✅ Enable connection caching
import { neonConfig } from "@neondatabase/serverless";
neonConfig.fetchConnectionCache = true;
// ✅ Use pooled connections
const pooledUrl = process.env.DATABASE_URL; // -pooler endpoint
// ❌ Don't use standard pg in edge runtime
// import { Pool } from "pg"; // Won't work in edgeConnection Management
连接管理
typescript
// ✅ Reuse connections in serverless
let cachedDb: ReturnType<typeof drizzle> | null = null;
function getDb() {
if (!cachedDb) {
const sql = neon(process.env.DATABASE_URL!);
cachedDb = drizzle(sql);
}
return cachedDb;
}
// ✅ Use transactions for consistency
await db.transaction(async (tx) => {
await tx.insert(users).values({ name: "John" });
await tx.insert(auditLog).values({ action: "user_created" });
});
// ❌ Don't forget to close pools in long-running processes
// await pool.end();typescript
// ✅ Reuse connections in serverless
let cachedDb: ReturnType<typeof drizzle> | null = null;
function getDb() {
if (!cachedDb) {
const sql = neon(process.env.DATABASE_URL!);
cachedDb = drizzle(sql);
}
return cachedDb;
}
// ✅ Use transactions for consistency
await db.transaction(async (tx) => {
await tx.insert(users).values({ name: "John" });
await tx.insert(auditLog).values({ action: "user_created" });
});
// ❌ Don't forget to close pools in long-running processes
// await pool.end();Branch Strategy
分支策略
yaml
Environments:
main: Production data
staging: Pre-production testing
dev: Shared development
feature/*: Individual features
preview/*: PR previews (auto-created)
Lifecycle:
- Create from parent on feature start
- Run migrations independently
- Test thoroughly
- Merge schema changes
- Delete after feature completionyaml
Environments:
main: Production data
staging: Pre-production testing
dev: Shared development
feature/*: Individual features
preview/*: PR previews (auto-created)
Lifecycle:
- Create from parent on feature start
- Run migrations independently
- Test thoroughly
- Merge schema changes
- Delete after feature completionCost Optimization
成本优化
typescript
// Development: Scale to zero
// - min_cu: 0.25
// - Suspend after 5 minutes idle
// Staging: Minimal always-on
// - min_cu: 0.5
// - Reduce during off-hours
// Production: Right-size baseline
// - min_cu: Based on traffic patterns
// - max_cu: Handle peak load
// Branch cleanup
// Delete unused preview branches after PR mergetypescript
// Development: Scale to zero
// - min_cu: 0.25
// - Suspend after 5 minutes idle
// Staging: Minimal always-on
// - min_cu: 0.5
// - Reduce during off-hours
// Production: Right-size baseline
// - min_cu: Based on traffic patterns
// - max_cu: Handle peak load
// Branch cleanup
// Delete unused preview branches after PR mergeEnvironment Variables
环境变量
Required Variables
必需变量
bash
undefinedbash
undefinedNeon connection strings
Neon connection strings
DATABASE_URL="postgresql://user:pass@ep-xxx-pooler.region.aws.neon.tech/db?sslmode=require"
DIRECT_URL="postgresql://user:pass@ep-xxx.region.aws.neon.tech/db?sslmode=require"
DATABASE_URL="postgresql://user:pass@ep-xxx-pooler.region.aws.neon.tech/db?sslmode=require"
DIRECT_URL="postgresql://user:pass@ep-xxx.region.aws.neon.tech/db?sslmode=require"
API access (for CLI/automation)
API access (for CLI/automation)
NEON_API_KEY="your_api_key"
NEON_API_KEY="your_api_key"
Project configuration
Project configuration
NEON_PROJECT_ID="your_project_id"
undefinedNEON_PROJECT_ID="your_project_id"
undefinedMulti-Environment Setup
多环境配置
bash
undefinedbash
undefined.env.local (development)
.env.local (development)
DATABASE_URL="postgresql://...dev-branch..."
DATABASE_URL="postgresql://...dev-branch..."
.env.staging
.env.staging
DATABASE_URL="postgresql://...staging-branch..."
DATABASE_URL="postgresql://...staging-branch..."
.env.production (via Vercel)
.env.production (via Vercel)
DATABASE_URL="postgresql://...main-branch..."
undefinedDATABASE_URL="postgresql://...main-branch..."
undefinedCommon Patterns
常用模式
API Route with Caching
带缓存的API路由
typescript
import { neon } from "@neondatabase/serverless";
export const runtime = "edge";
export async function GET() {
const sql = neon(process.env.DATABASE_URL!);
const users = await sql`SELECT * FROM users ORDER BY created_at DESC LIMIT 10`;
return Response.json(users, {
headers: {
"Cache-Control": "s-maxage=60, stale-while-revalidate",
},
});
}typescript
import { neon } from "@neondatabase/serverless";
export const runtime = "edge";
export async function GET() {
const sql = neon(process.env.DATABASE_URL!);
const users = await sql`SELECT * FROM users ORDER BY created_at DESC LIMIT 10`;
return Response.json(users, {
headers: {
"Cache-Control": "s-maxage=60, stale-while-revalidate",
},
});
}Server Actions (Next.js)
服务端动作(Next.js)
typescript
"use server";
import { neon } from "@neondatabase/serverless";
import { revalidatePath } from "next/cache";
export async function createUser(formData: FormData) {
const sql = neon(process.env.DATABASE_URL!);
const name = formData.get("name") as string;
const email = formData.get("email") as string;
await sql`INSERT INTO users (name, email) VALUES (${name}, ${email})`;
revalidatePath("/users");
}typescript
"use server";
import { neon } from "@neondatabase/serverless";
import { revalidatePath } from "next/cache";
export async function createUser(formData: FormData) {
const sql = neon(process.env.DATABASE_URL!);
const name = formData.get("name") as string;
const email = formData.get("email") as string;
await sql`INSERT INTO users (name, email) VALUES (${name}, ${email})`;
revalidatePath("/users");
}Connection Testing
连接测试
typescript
async function testConnection() {
const sql = neon(process.env.DATABASE_URL!);
try {
const result = await sql`SELECT version()`;
console.log("✅ Connected to Neon:", result[0].version);
return true;
} catch (error) {
console.error("❌ Connection failed:", error);
return false;
}
}typescript
async function testConnection() {
const sql = neon(process.env.DATABASE_URL!);
try {
const result = await sql`SELECT version()`;
console.log("✅ Connected to Neon:", result[0].version);
return true;
} catch (error) {
console.error("❌ Connection failed:", error);
return false;
}
}Troubleshooting
故障排查
Connection Issues
连接问题
typescript
// Check SSL requirement
const url = new URL(process.env.DATABASE_URL!);
if (!url.searchParams.has("sslmode")) {
url.searchParams.set("sslmode", "require");
}
// Verify endpoint type
// -pooler: For application queries
// direct: For migrations and admin tasks
// Test connectivity
import { neon } from "@neondatabase/serverless";
const sql = neon(process.env.DATABASE_URL!);
await sql`SELECT 1`; // Should succeedtypescript
// Check SSL requirement
const url = new URL(process.env.DATABASE_URL!);
if (!url.searchParams.has("sslmode")) {
url.searchParams.set("sslmode", "require");
}
// Verify endpoint type
// -pooler: For application queries
// direct: For migrations and admin tasks
// Test connectivity
import { neon } from "@neondatabase/serverless";
const sql = neon(process.env.DATABASE_URL!);
await sql`SELECT 1`; // Should succeedMigration Failures
迁移失败
bash
undefinedbash
undefinedUse direct connection for migrations
Use direct connection for migrations
export DIRECT_URL="postgresql://...direct-endpoint..."
npx prisma migrate deploy
export DIRECT_URL="postgresql://...direct-endpoint..."
npx prisma migrate deploy
Check migration status
Check migration status
npx prisma migrate status
npx prisma migrate status
Force reset (dev only)
Force reset (dev only)
npx prisma migrate reset
undefinednpx prisma migrate reset
undefinedPerformance Issues
性能问题
typescript
// Enable query logging
import { drizzle } from "drizzle-orm/neon-http";
const db = drizzle(sql, { logger: true });
// Check slow queries in Neon console
// Monitoring → Query Performance
// Add indexes
await sql`CREATE INDEX idx_users_email ON users(email)`;
// Use connection pooling
// Ensure using -pooler endpointThis skill provides comprehensive coverage of Neon serverless Postgres, including database branching, ORM integrations, serverless deployment patterns, and production best practices.
typescript
// Enable query logging
import { drizzle } from "drizzle-orm/neon-http";
const db = drizzle(sql, { logger: true });
// Check slow queries in Neon console
// Monitoring → Query Performance
// Add indexes
await sql`CREATE INDEX idx_users_email ON users(email)`;
// Use connection pooling
// Ensure using -pooler endpoint本技能全面覆盖了Neon serverless Postgres的使用,包括数据库分支、ORM集成、serverless部署模式和生产环境最佳实践。