Legan Studio
Все статьи
~ 6 мин чтения

Feature flags: GrowthBook, Unleash, Flagsmith

Feature flags на сайте: зачем нужны, как внедрить, сравнение GrowthBook, Unleash, Flagsmith, A/B-тесты, постепенный rollout, управление рисками.

  • веб
  • разработка
  • devops

Feature flags — переключатели, которые позволяют включать и выключать функциональность в проде без передеплоя. Запустили новую корзину, что-то сломалось — два клика, и все пользователи на старой. Это превращает страшный релиз в нестрашный, и для растущих продуктов это must-have.

Зачем нужны feature flags

СценарийЧто делает флаг
Постепенный rolloutсначала 1% пользователей, потом 10%, потом 100%
Отключение функции в случае проблеммгновенно выключить, не передеплоивая
A/B-тестыдве версии одной фичи, метрики какая лучше
Раздел по сегментамновая функция только для enterprise-плана
Включение по бета-программеконкретные emails видят то, чего другие не видят
Trunk-based developmentmerge в main без боязни сломать прод

Без флагов

Релиз → баг в проде → откат → расследование → fix → релиз. Между «обнаружили» и «починили» — час, иногда сутки. Пользователи злы.

С флагом: релиз → баг → выключили флаг (5 секунд) → пользователи на старой версии → расследование без давления.

Локальные флаги

В простейшем случае — .env:

NEXT_PUBLIC_FEATURE_NEW_CHECKOUT=true
NEXT_PUBLIC_FEATURE_AI_RECOMMENDATIONS=false
if (process.env.NEXT_PUBLIC_FEATURE_NEW_CHECKOUT === "true") {
  return <NewCheckout />;
}
return <OldCheckout />;

Минусы: чтобы включить/выключить — нужен передеплой. Нет сегментации (или вкл всем, или выкл всем). Не подходит для растущих команд.

Сравнение flag-сервисов

СервисOpen sourceSelf-hostedБесплатный планСложность
GrowthBookда (MIT)дадо 1 000 ивентов/мессредняя
Unleashда (Apache 2.0)даcommunity edition бесплатносредняя
Flagsmithда (BSD)дадо 50 000 запросов/меснизкая
LaunchDarklyнетнет$0 — нетнизкая (богатый UI)
ConfigCatнет (но есть free tier)нетдо 10 флаговнизкая
PostHog Feature Flagsдададо 1 млн ивентов/меснизкая

Для российского проекта самое разумное — GrowthBook или Unleash self-hosted (полностью бесплатно), либо PostHog если уже используете для аналитики.

GrowthBook — рекомендуем

Open source, фокус на A/B-тестах с интеграцией в аналитику.

docker run -d -p 3100:3000 -p 4100:3100 \
  -e MONGODB_URI=... growthbook/growthbook
import { GrowthBook } from "@growthbook/growthbook-react";

const gb = new GrowthBook({
  apiHost: "https://flags.example.ru",
  clientKey: "sdk-xxxxx",
  attributes: {
    id: user.id,
    plan: user.plan,
    country: "RU",
  },
});
await gb.loadFeatures();
import { useFeatureIsOn } from "@growthbook/growthbook-react";

function Checkout() {
  const newFlow = useFeatureIsOn("new-checkout");
  return newFlow ? <NewCheckout /> : <OldCheckout />;
}

В UI GrowthBook задаёте правила:

  • 50% пользователей → ON.
  • Юзеры с plan = "enterprise" → ON.
  • Юзеры из country = "RU" → OFF.
  • A/B-тест: 50% видят вариант A, 50% — B; меряем conversion.

Unleash

Похож на GrowthBook, фокус на feature toggles без A/B. Хорошо подходит для команд, где нужно много прав-управления (кто может включать какие флаги).

import { initialize } from "unleash-client";
const unleash = initialize({
  url: "https://unleash.example.ru/api/",
  appName: "my-site",
  customHeaders: { Authorization: "..." },
});
unleash.on("ready", () => {
  if (unleash.isEnabled("new-checkout", { userId })) {
    /* ... */
  }
});

Минус: меньше готовых функций для эксперимента, чем у GrowthBook.

Flagsmith

Самый простой UI, удобен для не-разработчиков (продакт-менеджер сам может включать).

import flagsmith from "flagsmith";
await flagsmith.init({ environmentID: "xxx" });
flagsmith.identify(user.id, { plan: user.plan });
if (flagsmith.hasFeature("new-checkout")) { /* ... */ }

SSR и флаги

Главная боль: на SSR нужно знать состояние флага до рендера, иначе будет flash контента (промигнёт старая версия, потом перерендерится новая).

В Next.js 15 — серверная инициализация:

// app/page.tsx (server component)
import { GrowthBook } from "@growthbook/growthbook";

async function getGrowthBook(userId: string) {
  const gb = new GrowthBook({ /* ... */ });
  await gb.loadFeatures();
  gb.setAttributes({ id: userId });
  return gb;
}

export default async function Page() {
  const gb = await getGrowthBook(getUserId());
  return gb.isOn("new-checkout") ? <NewCheckout /> : <OldCheckout />;
}

Для client components — гидрация с тем же стейтом, чтобы не мигало.

A/B-тесты правильно

Пара правил, без которых эксперимент бесполезен:

  1. Sample size — заранее посчитайте, сколько пользователей нужно для статистической значимости. Калькуляторы есть в GrowthBook.
  2. Один тест за раз — иначе не понятно, какая фича дала эффект.
  3. Минимум 2 недели — недельный цикл (выходные ≠ будни) должен пройти полностью.
  4. Метрика выбрана заранее — не подгоняйте, не ищите «какая метрика выиграла».
  5. Ноль = тоже результат — если фича не дала эффекта, нужно её откатить, не «всё равно зальём».

Risk management

Каждый флаг — потенциальный долг. Через месяц-два их становится 30, никто не помнит, что они делают, в коде ветвление на ветвление.

Правила гигиены:

  • Каждый флаг имеет owner и дата планируемого удаления.
  • Раз в спринт — ревью списка, удаление протухших.
  • Тесты пишем на обе ветки (if flag и else), чтобы при удалении флага не рассыпалось.
  • Не более 5-10 активных флагов на сервис одновременно.

Killswitch для критичных функций

Помимо обычных флагов имеет смысл выделить «аварийные выключатели» для критики:

  • disable-checkout — отключить оформление заказа при сбое платёжного шлюза.
  • disable-search — выключить поиск, если упал Elasticsearch.
  • read-only-mode — режим только-чтение при миграции БД.

Эти флаги не для экспериментов, а для инциден-response. Должны включаться за секунды, без согласований.

Стоимость

РешениеМесяц для 100 тыс. пользователей
GrowthBook self-hosted500-1500 ₽ (VPS)
Unleash communityто же
PostHog self-hosted2-5 тыс. ₽
LaunchDarklyот $1000
ConfigCat$99-799

Российским проектам — однозначно self-hosted, оплата зарубежных SaaS затруднена.

Итого

Feature flags — стандарт зрелого продукта. Без них релиз каждой фичи — нервный, с ними — рутина. Ставьте GrowthBook или Unleash, заведите дисциплину «каждый флаг с владельцем и датой смерти», и через полгода вы не вспомните, как жили без них.

Частые вопросы

Сколько флагов нормально иметь в проекте?

Активных — 5-15 на сервис в любой момент. Если становится больше — что-то идёт не так, превратили продукт в лоскутное одеяло. Каждый флаг должен иметь дату удаления (через 1-3 месяца после релиза). Долгоживущие флаги (например, разделение по тарифам) — это не feature flag, а конфигурация, выносите в отдельную таблицу.

Feature flags замедляют сайт?

Запросы к flag-серверу — да, каждый сетевой round-trip это latency. Решение: SDK кеширует флаги локально (5-30 секунд), плюс используется server-side rendering для первого запроса. На клиенте — periodic refetch в фоне. На правильно сконфигурированном GrowthBook overhead исчезающе мал — единицы миллисекунд.

Как тестировать фичу под флагом локально?

Override через query param или localStorage: ?gb=new-checkout принудительно включает флаг для текущего юзера. SDK должен это поддерживать (GrowthBook через forceFeatures). На staging — заводят отдельное окружение в flag-сервере с предсказуемыми правилами для QA.

A/B-тесты обязательно в flag-сервисе или можно самим?

Технически можно: рандомное распределение в коде + аналитика отдельно. Но статистический анализ (значимость, sample size, sequential testing) — это месяцы работы. Лучше взять GrowthBook или PostHog Experiments — там это решено и есть калькуляторы. Самописное A/B обычно даёт ложные результаты из-за статистических ошибок.

Как избежать flash контента при загрузке?

Серверный рендер — флаги загружаются на бэке до отдачи HTML, разметка приходит уже с правильной версией. На клиенте — hydration с тем же state. Если без SSR (SPA) — показывайте skeleton до загрузки флагов и только потом делайте решение, что показать. Не делайте мгновенный default fallback, иначе будет мигать.

Flag-сервис лежит — что показывать?

SDK всегда отдаёт fallback-значение, заданное в коде (обычно «функция выключена»). Поэтому даже если GrowthBook упал — продукт работает по последней закешированной конфигурации или с фолбэком. Главное — не делать критическую функциональность зависимой от ответа сервиса в реальном времени.

Можно ли использовать feature flags для permission/access control?

Нет. Это разные задачи. Permissions — это «может ли этот юзер видеть страницу X», управляется через RBAC и проверки на бэке. Feature flag — «включена ли вообще эта фича в проде». Использовать flag для прав — путь к утечке данных, потому что флаги легко обходятся клиентскими манипуляциями (override через query param). Для прав — отдельный механизм с проверкой на сервере.