1When do I need this?
- Structured data like users/orders/products
- Relationships between data matter (users - orders - products)
- Complex queries are needed (JOIN, GROUP BY, aggregation)
- Transaction guarantees are required (payments, inventory management)
2Key Services
PostgreSQL
Free, most popularOpen source. Rich in JSON, full-text search, and extension features. Recommended for most new projects.
MySQL
Free, many legacy systemsLong history and massive ecosystem. Widely used in WordPress and existing systems.
Supabase
Managed PostgreSQLPostgreSQL-based BaaS. Provides authentication, storage, and real-time features together.
PlanetScale
Managed MySQLMySQL compatible. Safely manage schema changes with branching.
3Pricing
- PostgreSQL / MySQL - Free when self-hosted (server costs separate)
- Supabase - Free tier: 500MB storage, 50K API requests/month
- PlanetScale - Free tier: 5GB storage, 1B row reads/month
4Connection Examples
FastAPI + asyncpg (Python)
# app/database.py
import asyncpg
from contextlib import asynccontextmanager
DATABASE_URL = "postgresql://user:password@localhost:5432/mydb"
pool = None
async def init_db():
global pool
pool = await asyncpg.create_pool(DATABASE_URL)
async def close_db():
await pool.close()
async def get_connection():
async with pool.acquire() as conn:
yield conn# app/main.py
from fastapi import FastAPI, Depends
from app.database import init_db, close_db, get_connection
app = FastAPI()
@app.on_event("startup")
async def startup():
await init_db()
@app.on_event("shutdown")
async def shutdown():
await close_db()
@app.get("/users")
async def get_users():
async with pool.acquire() as conn:
rows = await conn.fetch("SELECT id, name, email FROM users")
return [dict(r) for r in rows]
@app.post("/users")
async def create_user(name: str, email: str):
async with pool.acquire() as conn:
row = await conn.fetchrow(
"INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *",
name, email
)
return dict(row)Hono + postgres.js (TypeScript)
// src/db.ts
import postgres from 'postgres';
const sql = postgres('postgresql://user:password@localhost:5432/mydb');
export default sql;// src/index.ts
import { Hono } from 'hono';
import sql from './db';
const app = new Hono();
app.get('/users', async (c) => {
const users = await sql`SELECT id, name, email FROM users`;
return c.json(users);
});
app.post('/users', async (c) => {
const { name, email } = await c.req.json();
const [user] = await sql`
INSERT INTO users (name, email)
VALUES (${name}, ${email})
RETURNING *
`;
return c.json(user, 201);
});
export default app;Using an ORM is more convenient
In real projects, it's more common to use SQLAlchemy (Python) or Drizzle ORM (TypeScript) rather than writing raw SQL.