METABYTE
К списку статей

Лучший стек для соло SaaS в 2026: без боли и найма команды

Какой стек выбрать соло основателю SaaS в 2026? Практический рецепт: Next.js 15, Postgres (Neon), Stripe, R2, очереди. Архитектура, цены, подводные камни.

12 мая 202611 мин чтенияAI-research draft
Лучший стек для соло SaaS в 2026: без боли и найма команды

Ошибиться со стеком для соло SaaS — это потерять квартал разработки и кучу нервов на миграциях, переписываниях и горячих фикcах в ночь. В 2026 году опций стало больше, но и ловушек — тоже.

Если коротко: дефолтный стек для соло SaaS в 2026 — TypeScript-центричный. Next.js 15 на Vercel, Postgres (Neon/Supabase), Drizzle или Prisma, Stripe для биллинга, Cloudflare R2 для файлов, легкая очередь задач (Upstash Redis или Cloudflare Queues), Sentry + PostHog для наблюдаемости. Такой набор минимизирует инфраструктуру, ускоряет разработку и позволяет масштабироваться без переписывания ядра.

Базовый стек 2026: что брать «по умолчанию»

  • UI/SSR/API: Next.js 15 (App Router, Route Handlers, RSC по месту). Деплой на Vercel, Edge Runtime для легких эндпоинтов и аутентификации.
  • Язык: TypeScript 5.x. Линтинг — ESLint + Biome, тесты — Vitest, e2e — Playwright.
  • База данных: Postgres. Провайдер: Neon (serverless, auto-suspend) или Supabase (если важен RLS и real-time). Соединения через встроенный connection pooling.
  • ORM/миграции: Drizzle ORM (SQL-first миграции, прозрачные diff) или Prisma (богатая экосистема, Data Proxy). В соло-режиме Drizzle обычно короче путь до продакшена.
  • Очереди/фоновые задачи: Upstash Redis (HTTP, pay-per-req) или Cloudflare Queues + один воркер на CF Workers.
  • Файлы: Cloudflare R2 (S3 API без egress в CF), CDN — Cloudflare фронт перед Vercel.
  • Аутентификация: Auth.js (бывш. NextAuth) с email magic link + OAuth; альтернативно Clerk/Descope, но следите за lock-in.
  • Платежи: Stripe Billing (продукты/планы, купоны, налоговые правила). Webhook-и через отдельный endpoint с ретраями и идемпотентностью.
  • Email: Postmark или Resend (транзакционные). Для маркетинга — ConvertKit/Customer.io по мере роста.
  • Логи/ошибки: Sentry + Vercel/Cloudflare Logs. Трассировка — OpenTelemetry (через Sentry Performance или Honeycomb при необходимости).
  • Аналитика: PostHog (self-host позже) или Vercel Analytics. Минимум метрик — MAU, конверсия trial→paid, churn, LTV/CAC хотя бы грубо.

В нашем опыте как разработчиков, это покрывает 80% B2B/B2C микросервисов и multi-tenant SaaS. Дальше вы расширяете только по факту узких мест, а не «на всякий случай».

Архитектура: как течёт трафик и данные

Базовый поток (multi-tenant):

  1. Пользователь → Cloudflare CDN → Vercel (Next.js). SSR/ISR на публичных страницах, защищенные — через middleware и сессионные куки.
  2. API запросы из клиента идут в Next Route Handlers (/api/*). Валидация через Zod, аутентификация из сессионного токена.
  3. База: Postgres (Neon) через Drizzle. Все таблицы имеют org_id для изоляции арендаторов. Индексы на (org_id, id) и на поля фильтрации.
  4. Тяжелые задачи (экспорт, интеграции, email) кладём в очередь (Upstash Redis). Воркер (Vercel Cron или отдельный CF Worker) обрабатывает задачи с идемпотентностью.
  5. Платежи: Stripe Checkout/Billing Portal. Webhook → валидация подписи → запись в subscriptions → постановка синхронизации в очередь.
  6. Файлы: загрузка на R2 через pre-signed URL. Метаданные — в Postgres.
  7. Observability: Sentry для ошибок, PostHog события для продукта.

Webhook Stripe: безопасно и идемпотентно

// app/api/stripe/webhook/route.ts (Next.js 15, Edge disabled — нужен Node runtime)
import { NextRequest, NextResponse } from 'next/server';
import Stripe from 'stripe';
import { drizzleDb } from '@/server/db';
import { eq } from 'drizzle-orm';
import { subscriptions, webhookEvents } from '@/server/schema';
import { enqueue } from '@/server/queue';

export const config = { runtime: 'nodejs' };

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-06-20',
});

export async function POST(req: NextRequest) {
  const sig = req.headers.get('stripe-signature') ?? '';
  const raw = await req.text();
  let event: Stripe.Event;

  try {
    event = stripe.webhooks.constructEvent(
      raw,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET!
    );
  } catch (err) {
    return NextResponse.json({ error: 'Invalid signature' }, { status: 400 });
  }

  // Идемпотентность на уровне БД: не обрабатываем одно событие дважды
  const exists = await drizzleDb
    .select()
    .from(webhookEvents)
    .where(eq(webhookEvents.id, event.id));

  if (exists.length) return NextResponse.json({ ok: true });

  await drizzleDb.insert(webhookEvents).values({ id: event.id, type: event.type });

  switch (event.type) {
    case 'customer.subscription.updated':
    case 'customer.subscription.created': {
      const sub = event.data.object as Stripe.Subscription;
      await drizzleDb
        .insert(subscriptions)
        .values({
          orgId: sub.metadata.org_id!,
          stripeSubId: sub.id,
          status: sub.status,
          currentPeriodEnd: new Date(sub.current_period_end * 1000),
        })
        .onConflictDoUpdate({
          target: subscriptions.stripeSubId,
          set: {
            status: sub.status,
            currentPeriodEnd: new Date(sub.current_period_end * 1000),
          },
        });
      await enqueue('sync-seat-quotas', { orgId: sub.metadata.org_id });
      break;
    }
    case 'invoice.payment_failed': {
      const inv = event.data.object as Stripe.Invoice;
      await enqueue('notify-payment-failed', { customerId: inv.customer });
      break;
    }
    default:
      break;
  }

  return NextResponse.json({ received: true });
}

Здесь важное: Node runtime для верификации подписи, запись идемпотентности в БД, а тяжелую бизнес-логику — в фоновую задачу. Через год вы себе за это пожмёте руку.

Альтернативы и компромиссы: не только Next.js

Иногда «дефолт» не подходит. Ниже — практичное сравнение четырех рабочих стеков.

СтекСкорость написания фичСтоимость на стартеМасштаб до 50k MAUЛок-инКомментарий
Next.js + Vercel + Postgres (Neon)высокаянизкаяхорошая (SSR/ISR, serverless)умеренныйЛучший дефолт для TypeScript-мыслителей. Много плагинов, быстрый деплой.
Hono/Workers + CF D1/Hyperdrive + R2средняяочень низкаяотличная на edgeвыше среднегоИдеален для latency-чувствительных проектов. Придётся принять особенности CF экосистемы.
Rails 8 + Hotwire + Postgres (Fly.io)высокаянизкаяхорошая (монолит)низкийСтабильная классика. Биллинг, фоновые джобы Sidekiq. Отличный DX для одного человека.
Django + HTMX + Postgres (Railway/Fly)средняянизкаяхорошаянизкийБыстро, предсказуемо, много пакетов. Чуть тяжелее UI-слой.

Как выбирать:

  • Вы — сильный в TS/React и нужен богатый UI? Берите Next.js.
  • Нужен минимальный отклик по всему миру и дешёвый рантайм без холодных стартов? Workers + Hono.
  • Хотите меньше JS и больше «из коробки»: формочки, фоновые задачи, админка? Rails/Django.

Отдельно про вендор-локин: он реален прежде всего в хранении данных и проприетарных фичах провайдера. Мы разбирали общий подход к локину в заметке о базах и платформах — посмотрите наши аргументы про миграции и слой абстракций: сравнение вендор-локина.

Данные, многотенантность и модель прав

Проще всего стартовать с row-level tenancy:

  • Каждая таблица имеет org_id. Индексы: (org_id, id) и на популярные фильтры.
  • В коде — обязательная прокладка where org_id = session.org_id в каждом запросе. Выносите это в хелпер-репозиторий.
  • Если используете Supabase — включите RLS-политики для API-доступа.

Схема (упрощённо):

  • organizations (id, name, owner_user_id, stripe_customer_id)
  • users (id, email, name)
  • org_members (org_id, user_id, role) — индекс (org_id, user_id)
  • subscriptions (org_id, stripe_sub_id, status, current_period_end)
  • projects (id, org_id, name, created_at)
  • Бизнес-таблицы с org_id и created_at.

И два правила, которые экономят недели:

  • Идемпотентность везде, где есть внешние вызовы (Stripe, Slack, GitHub Apps).
  • Старайтесь не хранить вычислённые агрегаты без нужды. Если понадобятся — добавьте материализованные представления и крон на рефреш.

Нужен поиск? Для начала хватит Postgres trigram (pg_trgm). Если требуется сложная подсветка и синонимы — Typesense/Meilisearch. Векторный поиск? Сначала спросите себя: действительно ли пользователю нужна «AI-подсказка здесь и сейчас», или хватит фильтров. Мы видели слишком много проектов, где модный инструмент ради инструмента сжигал бюджет.

CI/CD и инфраструктура без DevOps-диплома

  • Репозиторий: GitHub. CI: GitHub Actions (линт, тесты, сборка). Деплой триггером на Vercel.
  • Миграции: Drizzle drizzle-kit в postbuild, авто-применение на проде через CLI с защитой (только «вперёд», откат — вручную с бэкапом).
  • Секреты: Vercel Env + Doppler/1Password CLI локально.
  • Кроны: Vercel Cron или Cloudflare Cron Triggers.
  • Мониторинг аптайма: Better Stack/UptimeRobot.

Минималистичный pipeline для миграций:

yarn drizzle:generate && yarn drizzle:migrate
# в CI — только generate и миграции на staging; в прод — вручную через approve job

На ранних этапах IaC (Terraform/Pulumi) можно не тащить. Как только у вас 3+ окружения и 2+ провайдера — фиксируйте инфраструктуру кодом, иначе одна «ручная правка» ночью незаметно вырастет в несогласованность конфигов.

Что ломается в продакшене

  • Соединения с Postgres у serverless-рантайма. Решение: использовать HTTP-пулы Neon/Prisma Data Proxy, ограничить параллелизм, кэшировать горячие запросы.
  • Webhook-и Stripe по умолчанию без идемпотентности. Решение: таблица webhook_events, уникальный ключ на id, повторы — 200 OK без побочек.
  • Долгие функции на edge/runtime. Решение: тяжелое — только в очереди. На API — таймаут 5–10 с максимум, дружелюбные ошибки пользователю.
  • Изображения и большие файлы через Next. Решение: всегда direct upload на R2/S3 с pre-signed URL.
  • Кэш-стратегии. ISR-страницы без инвалидации после мутаций — получаются «фантомные» данные. Решение: revalidateTag/webhook-ревалидейшн.
  • Лимиты провайдеров (RPS, egress). Решение: пейджер на превышение, план миграции (например, с Vercel Images → Cloudflare Images) заранее.

И классика жанра: сообщения об ошибках. Пользователь должен понять, что произошло и что делать дальше. Техническая точность + человеческий язык. Если сомневаетесь — посмотрите наш разбор про то, как писать понятные ошибки. Одно вежливое предложение иногда экономит десятки тикетов саппорта.

Деньги и сроки: во что это обойдётся

Реалистичный бюджет для соло в 2026 (в месяц):

  • Vercel Pro: $20–40 (пока трафик мал).
  • Neon/Supabase: $0–29 (serverless, auto-suspend).
  • Cloudflare R2: $5–20 (хранение + редкие egress).
  • Upstash Redis: $0–10 (очереди по HTTP).
  • Postmark/Resend: $10–30 (транзакционные письма).
  • Sentry: $0–26 (Basic/Team, зависит от объёма событий).
  • PostHog Cloud: $0–40 (первые ивенты бесплатны).

Итого: $50–150/мес на ранних этапах. Stripe возьмёт свой процент только при оплатах. При 10k MAU и активном продукте счёт перевалит за $200–400/мес, но к этому времени должен быть MRR.

Стоимость разработки фич: в соло-режиме ориентируйтесь на 2–4 недели до MVP (аутентификация, биллинг, 2–3 ключевые фичи, аналитика, базовый маркетинг-сайт). Дальше спринты по 1–2 недели на улучшения и интеграции.

Где легко переплатить:

  • Ранний переход на микросервисы. Монолит быстрее, дешевле и проще дебажить.
  • Премиальные пайплайны ML/векторные кластеры «на вырост». Сначала докажите ценность пользователю.
  • Сложные WAF/CDN-топологии без трафика. Cloudflare по умолчанию покрывает 90% кейсов.

Когда уместно отойти от дефолта

  • Ультра-низкие задержки по миру и event-driven ядро: берите Hono/Workers + Queues, храните данные в D1/Hyperdrive+Postgres, файлы в R2. У вас меньше «магии», больше контроля.
  • Внутренние админки, формы, Excel-подобная логика: Rails/Django могут ускорить поставку фич. Hotwire/HTMX — честный путь без SPA-сложности.
  • Жёсткие требования комплаенса/он-прем: Docker + Traefik, самоуправляемый Postgres, Keycloak/ORY для auth, IaC с Terraform с первого дня. Соло такое вытянуть можно, но скорость упадёт.

И да, если у вас токены, агенты и локальные LLM — первый вопрос: они вообще будут бежать в проде? Мы разбирали распространённый анти-паттерн «запустили локальную LLM — в прод не взлетело» — смотрите разбор типичных ошибок в кейсе про локальные модели.

Мини-шпаргалка по настройкам

  • Next.js: включайте experimental.serverActions только точечно; ISR для маркетинговых страниц, SSR — для дашборда.
  • Куки: Secure, HttpOnly, SameSite=Lax. Крутите Session в Redis, если нужен logout из всех устройств.
  • Безопасность: CSP, X-Frame-Options: DENY, ограничьте upload MIME.
  • Ограничение запросов: rate-limit по IP + по org_id. Для публичных API — HMAC-подписи и timestamp.
  • Бэкапы: ежедневные снапшоты Postgres + проверка восстановления на staging раз в 2 недели (иначе бэкапов «нет»).

Небольшая сухая шутка, чтобы разрядить инженерный воздух: лучше иметь два бэкапа и ни разу их не восстанавливать, чем один — и восстанавливать каждый понедельник.

FAQ

Какой стек выбрать, если я не люблю React?

Если хочется меньше JS и больше “скелета из коробки”, берите Rails 8 + Hotwire или Django + HTMX. Оба отлично справляются с типичным SaaS: формы, биллинг, фоновые задания, админка.

Supabase или Neon?

Supabase удобнее, если вам нужны RLS, Storage и Realtime сразу. Neon — отличный серверлесс Postgres без всего лишнего и с хорошим autosuspend. Для соло не ошибётесь ни с одним, но RLS из коробки у Supabase — сильный аргумент для простых API.

Drizzle или Prisma?

Drizzle — проще миграции и ближе к SQL, быстрый старт. Prisma — мощные генераторы, богатая экосистема и удобные типы. Для очень маленьких проектов Drizzle короче путь; если у вас сложные реляции и любитe DX Prisma — берите Prisma Data Proxy.

Куда выносить фоновые задачи на Vercel?

Два пути: Upstash Redis + Vercel Cron/Serverless в роли воркера или Cloudflare Queues + отдельный Worker. Второй путь чуть надёжнее под нагрузкой, но требует настроек вне Vercel.

Как избежать вендор-локина?

  • Данные — в Postgres (SQL dump — ваш друг).
  • Файлы — S3-совместимое хранилище (R2/S3) с минимальной логикой на стороне провайдера.
  • Сервисы типа аутентификации — держите возможность fallback на Auth.js.
  • Контракты — через интерфейсы/адаптеры в коде. Подробную аргументацию см. в нашей статье о локине по базам.

Когда переходить с монолита на микросервисы?

Когда упрётесь в независимые темпы релизов для разных доменов и появится реальная команда. До этого — монолит быстрее и дешевле. Горизонтальный скейл API обычно решается кэшем/очередями.

Ключевые выводы

  • Дефолт 2026 для соло SaaS: Next.js + Postgres (Neon/Supabase) + Stripe + R2 + простые очереди.
  • Проектируйте с многотенантностью в уме: org_id везде, индексы, идемпотентность событий.
  • Фоновые задачи — отдельно от API. Таймауты и дружелюбные ошибки на пользовательской поверхности.
  • Сначала монолит. Микросервисы только по реальной необходимости и метрикам.
  • Логи, метрики, бэкапы — не «потом». Минимум Sentry + PostHog + ежедневные снапшоты.
  • Считайте деньги: на старте инфраструктура $50–150/мес без искусственных «облаков на вырост».

Если вы строите SaaS и хотите пройти этот путь без лишних «переизобретений велосипеда», напишите нам. MTBYTE спроектирует архитектуру, поднимет прод и поможет с первым релизом — перейдите на /contact.

СЛЕДУЮЩИЙ ШАГ

Понравилось как мыслим?

Применяем те же принципы в клиентских проектах: AI, автоматизации, продукты, которые не умирают после релиза.