Налаштування Feature Flags
Feature flags (прапори функцій) дозволяють розгортати код без випуску функцій: вмикати функції для окремих користувачів, сегментів аудиторії або відсотків трафіку без нових розгортань.
Для чого потрібні feature flags
- Trunk-based development — усі працюють в main/master, незавершені функції приховані за прапором
- Canary releases — спочатку 1% користувачів, потім 10%, потім всім
- A/B тестування — різні версії для різних сегментів
- Kill switch — миттєве вимкнення проблемної функції без розгортання
- Beta-програми — включення для конкретних облікових записів
Self-hosted: Unleash
# Docker Compose
cat > docker-compose.yml << 'EOF'
services:
db:
image: postgres:16
environment:
POSTGRES_DB: unleash
POSTGRES_USER: unleash
POSTGRES_PASSWORD: secret
volumes:
- pg_data:/var/lib/postgresql/data
unleash:
image: unleashorg/unleash-server:latest
ports:
- "4242:4242"
environment:
DATABASE_URL: postgresql://unleash:secret@db/unleash
INIT_CLIENT_API_TOKENS: "default:development.unleash-token"
depends_on:
- db
volumes:
pg_data:
EOF
docker compose up -d
Інтеграція в Next.js:
// lib/unleash.ts
import { initialize, isEnabled, getVariant } from 'unleash-client';
export const unleash = initialize({
url: 'http://unleash:4242/api',
appName: 'my-nextjs-app',
customHeaders: { Authorization: process.env.UNLEASH_TOKEN! },
});
// Використання в Server Component
export async function isFeatureEnabled(flag: string, userId?: string) {
await unleash.isReady();
return isEnabled(flag, { userId });
}
// app/page.tsx (Server Component)
import { isFeatureEnabled } from '@/lib/unleash';
export default async function HomePage() {
const showNewHero = await isFeatureEnabled('new-hero-section', userId);
return showNewHero ? <NewHeroSection /> : <OldHeroSection />;
}
Cloud: Growthbook (Open Source SaaS)
# Self-hosted
docker run -d \
-e MONGODB_URI=mongodb://mongo/growthbook \
-e APP_ORIGIN=http://localhost:3000 \
-p 3000:3000 \
growthbook/growthbook:latest
// SDK для React
import { GrowthBook, GrowthBookProvider, useFeatureValue } from '@growthbook/growthbook-react';
const gb = new GrowthBook({
apiHost: 'https://cdn.growthbook.io',
clientKey: process.env.NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY,
enableDevMode: process.env.NODE_ENV !== 'production',
trackingCallback: (experiment, result) => {
// Відправляємо в аналітику
gtag('event', 'experiment_viewed', {
experiment_id: experiment.key,
variant_id: result.key,
});
},
});
// Провайдер
function App({ Component, pageProps }) {
return (
<GrowthBookProvider growthbook={gb}>
<Component {...pageProps} />
</GrowthBookProvider>
);
}
// Використання в компоненті
function PricingPage() {
const showAnnualPricing = useFeatureValue('annual-pricing', false);
const ctaText = useFeatureValue('cta-text', 'Get Started');
return (
<div>
<button>{ctaText}</button>
{showAnnualPricing && <AnnualPricingSection />}
</div>
);
}
Прапори з таргетингом (PostHog)
// PostHog: feature flags + аналітика в одному інструменті
import PostHog from 'posthog-node';
const client = new PostHog(process.env.POSTHOG_API_KEY!, {
host: 'https://app.posthog.com'
});
// Таргетинг за властивостями користувача
const isEnabled = await client.isFeatureEnabled(
'new-checkout-flow',
userId,
{
// PostHog перевірить проти правил прапора
personProperties: {
plan: user.plan, // 'pro' | 'enterprise'
country: user.country,
created_at: user.createdAt,
}
}
);
Патерни використання
Поступовий rollout:
0% → розгортання коду за прапором
1% → включення для 1% користувачів, моніторинг помилок
10% → розширення, моніторинг метрик
50% → половинний rollout, остаточна перевірка
100% → повний rollout
→ видалення прапора з коду (прапори-зомбі — технічний борг)
Життєвий цикл прапора:
// Прапори повинні мати термін експлуатації
// Створюємо з датою закінчення:
// "new-onboarding-flow" → expires: 2024-03-01
// Після цієї дати — видалити прапор з коду
Налаштування self-hosted Unleash або Growthbook з інтеграцією в додаток — 1–2 робочих дні.







