EvolCode
треки/Базы данных·04 / 07
12 мин чтения

Где держать базу данных — Postgres на Neon

Ты собрал MVP. Файл prisma/dev.db лежит рядом с кодом, всё работает. Деплоишь на сервер — и через неделю обнаруживаешь: контейнер пересоздался, файл с базой стёрся, юзеры пропали. Или: запустил второй инстанс приложения для нагрузки — у каждого инстанса своя БД, юзеры видят разные данные. Или просто: 50 человек одновременно зашли на сайт, SQLite заблокировался, всё упало. Это не страшилки — это реальные сценарии того, почему файловая БД рядом с приложением — для разработки, не для людей в интернете.

Почему SQLite — это для разработки, а не продакшна

SQLite — это не сервер, это ОДИН файл с расширением .db. Все запросы идут через файловые операции операционной системы. Плюсы для разработки: ничего не настраивать, скопировал файл — скопировал базу. Минусы для продакшна: если контейнер умер — файл умер вместе с ним. Если два процесса пишут одновременно — один блокирует другой. Если масштабируешься на несколько серверов — каждый сервер думает, что у него своя база. Бэкапов автоматических нет, репликации нет, удалённого доступа нет. Для локалки и тестов — топ. Для тысячи юзеров — катастрофа, ждущая своего часа.

PostgreSQL и почему именно он

PostgreSQL — это полноценная база-сервер. Запускается отдельным процессом (часто на отдельной машине), приложение подключается по сети. Поддерживает тысячи одновременных соединений, репликацию, бэкапы, точки восстановления, сложные запросы, json-поля, расширения для геоданных и поиска. На нём работают Apple, Spotify, Reddit, Instagram. И что важно для тебя — Prisma поддерживает Postgres как первоклассный язык. Переезд с SQLite на Postgres — это смена одной строки в schema.prisma и одной миграции.

Где хостить Postgres — и почему Neon

Можно поднять Postgres самому на VPS за $5/мес — но придётся самому делать бэкапы, мониторить, обновлять, чинить. На раннем стартапе это потерянное время. Можно взять managed-сервис — Supabase, Railway, Render, Vercel Postgres, AWS RDS. Конкретно Neon выделяется тем, что он serverless: когда никто не пользуется — БД спит и не тратит твою квоту. Просыпается за ~300мс при первом запросе. Бесплатный план — 0.5 GB storage и 190 compute hours в месяц, этого хватит на несколько тысяч пользователей. Плюс branching: можно создать ветку БД для тестов, как ветку в Git. После Neon обратно не хочется.

Pooled vs Direct — два разных URL и зачем

В Neon тебе дают два connection string. Pooled — с "-pooler" в имени хоста, через PgBouncer. Direct — без него, прямое соединение. Зачем оба? Pooled нужен в продакшне на serverless-платформах вроде Vercel: каждая serverless-функция при старте открывает соединение к БД, и без пулера ты быстро упрёшься в лимит соединений. Pooler группирует короткие соединения в одно длинное. Direct нужен для миграций и Prisma Studio — пулер не пропускает некоторые служебные команды Postgres. Поэтому в .env у тебя DATABASE_URL (pooled) и DIRECT_URL (direct).

Прямо на пальцах: переезд за 10 минут

Шаг 1: регистрируешься на neon.tech, создаёшь проект — выбирай регион ближе к серверу приложения. Шаг 2: копируешь оба URL — pooled и direct. Шаг 3: в .env меняешь DATABASE_URL="file:./dev.db" на pooled URL, добавляешь DIRECT_URL = direct URL. Шаг 4: в schema.prisma меняешь provider = "sqlite" на provider = "postgresql" и добавляешь directUrl = env("DIRECT_URL"). Шаг 5: удаляешь старую папку prisma/migrations (она была под SQLite). Шаг 6: запускаешь

$ npx prisma migrate dev --name init_postgres

Prisma создаёт схему в Neon. Готово.

Грабли, на которые наступают все

P1012 invalid datasource — провайдер в schema.prisma всё ещё "sqlite". Сохрани файл и попробуй снова. P1013 invalid port number — в connection string остались "..." или другие плейсхолдеры. Проверь, что URL — настоящий, скопированный из Neon целиком. EPERM operation not permitted на Windows — у тебя запущен npm run dev и файл prisma DLL занят. Закрой его перед миграцией: taskkill /F /IM node.exe. Too many connections под нагрузкой — забыл -pooler в DATABASE_URL, переключи на pooled.

примерprisma
// БЫЛО — SQLite, файл рядом с проектом
datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}
// .env: DATABASE_URL="file:./dev.db"


// СТАЛО — Postgres на Neon, два URL
datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")   // pooled, для приложения
  directUrl = env("DIRECT_URL")      // direct, для миграций
}
// .env:
// DATABASE_URL="postgresql://user:pass@host-pooler.neon.tech/db?sslmode=require"
// DIRECT_URL="postgresql://user:pass@host.neon.tech/db?sslmode=require"


// Бонус: что Postgres даёт нового по сравнению с SQLite
model User {
  id    String    @id @default(cuid())
  email String    @unique
  level UserLevel @default(intermediate)  // настоящие enum'ы
  bio   String?   @db.Text                 // длинный текст без лимита
}

enum UserLevel {
  beginner
  intermediate
  advanced
}

schema.prisma — было / стало

главное
  • 01SQLite — для локалки. На продакшене с пользователями нужна сетевая БД
  • 02Postgres — стандарт индустрии: репликация, бэкапы, тысячи соединений
  • 03Neon = serverless Postgres со scale-to-zero и веткованием БД как в Git
  • 04В .env держи два URL: DATABASE_URL (pooled) и DIRECT_URL (direct)
  • 05Pooled — для приложения, Direct — для миграций и Prisma Studio
  • 06Миграция SQLite → Postgres = смена provider и одна команда prisma migrate dev
  • 07Postgres даёт enum’ы и @db.Text — то, чего в SQLite нет
проверь себя
01Почему в продакшене лучше не держать базу как файл рядом с приложением?
02Зачем в .env при работе с Neon нужны ДВА URL — DATABASE_URL и DIRECT_URL?
03Что значит "scale to zero" у Neon?
04Получил ошибку P1013 invalid port number при миграции. Что обычно не так?
следующий урок: Транзакции и ACID — почему деньги не пропадают