🗄️ 데이터베이스

Neon

Serverless PostgreSQL

서버리스 PostgreSQL 플랫폼으로, Git처럼 데이터베이스를 브랜칭하고, 사용하지 않을 때 자동으로 스케일-투-제로하며, 필요시 자동 확장되는 클라우드 네이티브 PostgreSQL입니다.

📖 상세 설명

Neon은 2021년 PostgreSQL 핵심 개발자들이 설립한 스타트업이 만든 서버리스 PostgreSQL 플랫폼입니다. 기존 AWS RDS나 Cloud SQL과 달리 컴퓨팅과 스토리지가 분리되어 있어 트래픽이 없을 때 0원, 급증하면 자동 확장되는 진정한 서버리스 모델을 제공합니다.

핵심 기능: Database Branching

Git 브랜치처럼 DB를 복제해 개발/스테이징 환경을 즉시 생성합니다. Copy-on-Write로 프로덕션 데이터 전체 복사 없이 브랜치 생성 가능.

Neon 핵심 기능

🌿
Database Branching
Git처럼 DB 브랜치 생성
📉
Scale to Zero
미사용 시 자동 종료
📈
Auto-scaling
트래픽 따라 자동 확장
Point-in-Time Recovery
특정 시점 복구
🐘
100% PostgreSQL
완전한 PG 호환성
🔌
Serverless Driver
Edge/Serverless 최적화

💻 코드 예제

1. Neon Serverless Driver (Edge 환경)

TypeScript (Vercel Edge Functions)
import { neon } from '@neondatabase/serverless'; // Neon Serverless Driver - HTTP 기반, 웹소켓 불필요 const sql = neon(process.env.DATABASE_URL!); export const config = { runtime: 'edge' }; export default async function handler(req: Request) { // 단일 쿼리 (HTTP fetch 기반) const posts = await sql` SELECT id, title, created_at FROM posts WHERE published = true ORDER BY created_at DESC LIMIT 10 `; // 파라미터화된 쿼리 (SQL Injection 방지) const userId = 123; const userPosts = await sql` SELECT * FROM posts WHERE author_id = ${userId} AND published = true `; return Response.json({ posts, userPosts }); } // 트랜잭션이 필요한 경우 (HTTP Transaction) async function transferCredits(fromId: number, toId: number, amount: number) { const sql = neon(process.env.DATABASE_URL!, { fetchOptions: { cache: 'no-store' } }); // BEGIN/COMMIT/ROLLBACK 대신 단일 요청으로 처리 const result = await sql.transaction([ sql`UPDATE users SET credits = credits - ${amount} WHERE id = ${fromId}`, sql`UPDATE users SET credits = credits + ${amount} WHERE id = ${toId}`, sql`INSERT INTO transfers (from_id, to_id, amount) VALUES (${fromId}, ${toId}, ${amount})`, ]); return result; }

2. Node.js 환경 (기존 pg 드라이버 호환)

TypeScript
import { Pool } from '@neondatabase/serverless'; import { drizzle } from 'drizzle-orm/neon-serverless'; import ws from 'ws'; // 웹소켓 설정 (Node.js 환경) import { neonConfig } from '@neondatabase/serverless'; neonConfig.webSocketConstructor = ws; // Connection Pool 사용 (기존 pg와 동일한 API) const pool = new Pool({ connectionString: process.env.DATABASE_URL }); // Drizzle ORM과 통합 const db = drizzle(pool); async function getUsers() { const client = await pool.connect(); try { await client.query('BEGIN'); const { rows: users } = await client.query(` SELECT u.*, COUNT(p.id) as post_count FROM users u LEFT JOIN posts p ON u.id = p.author_id GROUP BY u.id `); await client.query('COMMIT'); return users; } catch (e) { await client.query('ROLLBACK'); throw e; } finally { client.release(); } }

3. Database Branching (CLI)

Neon CLI
# Neon CLI 설치 npm install -g neonctl # 로그인 neonctl auth # 프로젝트 생성 neonctl projects create --name my-app # 브랜치 목록 확인 neonctl branches list --project-id # 프로덕션에서 개발 브랜치 생성 (Copy-on-Write) neonctl branches create \ --project-id \ --name feature/new-feature \ --parent main # 특정 시점으로 브랜치 생성 (Point-in-Time) neonctl branches create \ --project-id \ --name recovery/before-migration \ --parent main \ --at "2024-01-15T10:30:00Z" # 브랜치 연결 문자열 확인 neonctl connection-string --branch feature/new-feature # 브랜치 삭제 neonctl branches delete feature/new-feature

4. Vercel + Neon 통합 (Preview Deployments)

vercel.json
{ "build": { "env": { "DATABASE_URL": "@neon_database_url" } } }
GitHub Actions (Preview Branch 자동 생성)
name: Create Neon Branch for PR on: pull_request: types: [opened, synchronize] jobs: create-branch: runs-on: ubuntu-latest steps: - name: Create Neon Branch uses: neondatabase/create-branch-action@v4 with: project_id: ${{ secrets.NEON_PROJECT_ID }} branch_name: preview/pr-${{ github.event.pull_request.number }} api_key: ${{ secrets.NEON_API_KEY }} - name: Run Migrations run: | DATABASE_URL=${{ steps.create-branch.outputs.db_url }} \ npx prisma migrate deploy - name: Comment PR with DB URL uses: actions/github-script@v6 with: script: | github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `Preview DB: \`${{ steps.create-branch.outputs.branch_id }}\`` })

5. pgvector와 AI 임베딩

SQL + TypeScript
-- Neon에서 pgvector 활성화 CREATE EXTENSION IF NOT EXISTS vector; -- 임베딩 테이블 생성 CREATE TABLE documents ( id SERIAL PRIMARY KEY, content TEXT, embedding vector(1536) -- OpenAI ada-002 ); -- HNSW 인덱스 (빠른 유사도 검색) CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops); -- TypeScript에서 사용 import { neon } from '@neondatabase/serverless'; import OpenAI from 'openai'; const sql = neon(process.env.DATABASE_URL!); const openai = new OpenAI(); async function semanticSearch(query: string) { // 쿼리 임베딩 생성 const response = await openai.embeddings.create({ model: 'text-embedding-ada-002', input: query, }); const embedding = response.data[0].embedding; // 유사도 검색 const results = await sql` SELECT id, content, 1 - (embedding <=> ${JSON.stringify(embedding)}::vector) as similarity FROM documents WHERE 1 - (embedding <=> ${JSON.stringify(embedding)}::vector) > 0.7 ORDER BY embedding <=> ${JSON.stringify(embedding)}::vector LIMIT 5 `; return results; }

💬 현업 대화 예시

DevOps 엔지니어
"Neon 쓰면 트래픽 없을 때 자동으로 꺼지니까 개발 DB 비용이 거의 0이야. RDS처럼 항상 켜놓을 필요 없어."
백엔드 개발자
"Database Branching이 진짜 좋아. PR마다 프로덕션 데이터로 테스트할 수 있고, 머지하면 브랜치 자동 삭제되게 해놨어."
풀스택 개발자
"Vercel Edge Functions에서 DB 연결하려면 웹소켓이 안 되잖아. Neon Serverless Driver는 HTTP 기반이라 Edge에서도 동작해."
테크 리드
"Cold Start가 있긴 한데 첫 연결 후에는 빨라. 프로덕션이면 스케일-투-제로 비활성화하고, 개발 환경만 켜두면 돼."

⚠️ 주의사항

Cold Start 지연

Scale-to-Zero 후 첫 연결 시 수 초의 Cold Start가 있습니다. 프로덕션에서는 최소 인스턴스를 1개로 설정하거나 Warm 옵션을 고려하세요.

연결 제한

서버리스 특성상 Connection Pool 크기에 제한이 있습니다. Connection Pooling(PgBouncer 내장)을 활용하고, Serverless Driver 사용을 권장합니다.

브랜치 스토리지 비용

브랜치는 Copy-on-Write지만 변경된 데이터는 별도 저장됩니다. 오래된 브랜치나 미사용 브랜치는 정기적으로 삭제하세요.

🔗 관련 용어

📚 더 배우기