Базы данных: SQLite vs Postgres vs «что попало»
Когда твой сайт должен помнить пользователей и заказы — нужна база данных. Выбор первой БД часто пугает: «MySQL? Postgres? Mongo?». Разберём по задачам, чтобы ты выбирал осознанно.
SQL vs NoSQL
SQL-базы (Postgres, SQLite, MySQL) — таблицы со строгими полями, связи между таблицами через id. NoSQL (MongoDB, Firestore) — гибкие документы (как JSON), без жёсткой схемы. SQL побеждает в 90% случаев — большинство данных по природе табличные (пользователи, заказы, сообщения). NoSQL хорош для специфических кейсов: логи, контент с переменной структурой, real-time чаты.
SQLite — для старта
SQLite — это БД В ОДНОМ ФАЙЛЕ. Никакого сервера, никакой настройки — просто файл .db. Идеально для пет-проектов, локальной разработки, прототипов. Лимит на запись (один писатель за раз) делает её плохой для multi-user продакшна, но для всего остального — золото. EvolCode сейчас на SQLite, и это норма для начала.
Postgres — для прода
PostgreSQL — индустриальный стандарт open-source SQL. Поддерживает всё: транзакции, сложные запросы, full-text поиск, JSON-колонки, миллионы пользователей, высокую нагрузку. На бесплатных хостингах часто доступен (Supabase, Neon, Railway дают бесплатный Postgres). Когда переезжать с SQLite на Postgres? Когда выходишь в прод и ждёшь больше 10 одновременных пользователей.
ORM или сырой SQL
ORM (Object-Relational Mapper) — библиотека которая позволяет работать с БД через объекты JS, не SQL. В JS экосистеме популярны: Prisma (топ-1 для Next.js), Drizzle (легче), TypeORM (классика). Преимущества: типы из коробки, миграции, автокомплит. Недостаток: ещё одна абстракция, нужно учить. Сырой SQL быстрее и гибче, но без типов и миграций. Для начала — Prisma.
Где хостить
SQLite — нигде, файл лежит рядом с сайтом (на VPS или Vercel блочном хранилище). Postgres — Supabase (бесплатно до 500MB), Neon (бесплатно до 0.5GB, serverless, очень популярен с Vercel), Railway ($5 кредит), сам Vercel предлагает Vercel Postgres. На VPS можешь поставить Postgres сам через apt — полный контроль, бесплатно.
// === schema.prisma ===
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite" // или "postgresql" для прода
url = env("DATABASE_URL")
}
// .env: DATABASE_URL="file:./dev.db"
// или DATABASE_URL="postgresql://user:pass@host:5432/db"
model User {
id String @id @default(cuid())
email String @unique
name String?
posts Post[] // связь один-ко-многим
createdAt DateTime @default(now())
}
model Post {
id String @id @default(cuid())
title String
content String
authorId String
author User @relation(fields: [authorId], references: [id])
published Boolean @default(false)
}
// === Использование ===
// npm i @prisma/client
// npx prisma migrate dev --name init # создаёт таблицы
import { PrismaClient } from '@prisma/client';
const db = new PrismaClient();
// Создать
const user = await db.user.create({
data: { email: 'a@e.com', name: 'Алексей' },
});
// Найти один
const u = await db.user.findUnique({ where: { email: 'a@e.com' } });
// Найти много
const users = await db.user.findMany({
where: { name: { contains: 'Ал' } },
orderBy: { createdAt: 'desc' },
take: 10,
});
// С отношением
const userWithPosts = await db.user.findUnique({
where: { id: '...' },
include: { posts: true }, // подгрузить связанные посты
});
// Обновить
await db.user.update({
where: { id: '...' },
data: { name: 'Новое имя' },
});
// Удалить
await db.user.delete({ where: { id: '...' } });
// Транзакция (несколько операций атомарно)
await db.$transaction([
db.user.update({ where: { id: '1' }, data: { balance: { decrement: 100 } } }),
db.user.update({ where: { id: '2' }, data: { balance: { increment: 100 } } }),
]);
// Если хоть одна упадёт — всё откатится.Prisma на практике — schema + клиент