Declarative Early Access Features
This document explains how to declaratively create and manage early access features in Studyflash using our PostHog integration.
Declarative Early Access Features
This document explains how to declaratively create and manage early access features in Studyflash using our PostHog integration.
Overview
Our early access features system provides a declarative, version-controlled approach to managing beta features and product experiments. Instead of manually creating features in PostHog's UI, you define features in code and CI automatically syncs them for you.
💡 Key Point: You typically don't need to run sync commands manually! Our CI pipeline automatically syncs feature changes when you merge to main branches.
Key Benefits
- Fully Automated: CI handles PostHog synchronization automatically
- Version Control: All feature definitions are stored in Git
- Multi-language Support: Define features in all supported languages
- Type Safety: Full TypeScript support with validation
- Consistency: Single source of truth for feature definitions
- Zero Manual Work: Just define features and merge - CI does the rest
Architecture
The system consists of three main components:
- Declarative Configuration (
src/early_access_features.ts) - The source of truth - CI/CD Pipeline - Automatically syncs changes when you merge
- Sync Script (
scripts/sync-early-access-features.ts) - Used by CI and for debugging
CI/CD Integration
The system is designed to be fully automated:
- 🔄 Auto-sync on merge: When you merge changes to main branches, CI automatically syncs features to PostHog
- 🔍 Validation in PRs: CI checks that your feature declarations are valid
- 🚫 No manual steps: You never need to run sync commands manually in normal workflows
- 🛡️ Safe operations: CI uses dry-run checks before applying changes
This means your typical workflow is simply: Code → PR → Merge → Done!
Adding New Features
1. Define Your Feature
Add your feature to the EARLY_ACCESS_FEATURES configuration in src/early_access_features.ts:
export const EARLY_ACCESS_FEATURES: Record<string, EarlyAccessFeatureDeclaration> = {
'my-new-feature': {
name: {
en: 'My New Feature',
de: 'Meine neue Funktion',
fr: 'Ma nouvelle fonctionnalité',
// ... other languages
},
description: {
en: 'An exciting new feature that improves user experience',
de: 'Eine aufregende neue Funktion, die die Benutzererfahrung verbessert',
fr: "Une nouvelle fonctionnalité passionnante qui améliore l'expérience utilisateur",
// ... other languages
},
stage: 'beta', // 'concept' | 'alpha' | 'beta' | 'general-availability'
},
};
2. Feature Stages
Choose the appropriate stage for your feature:
| Stage | Description | User Experience |
|---|---|---|
concept | Features in planning/development | Appears in "Coming Soon" - users can register interest |
alpha | Internal testing phase | Limited availability |
beta | Public testing phase | Users can opt-in to test |
general-availability | Production-ready | Available to all users |
Refer to PostHog's Early Access Feature Management documentation for detailed information about feature stages.
3. Naming Convention
- Use kebab-case for feature keys (
my-new-feature) - Keys should be descriptive and unique
- Keys become PostHog feature flag names
Manual Syncing (Development/Debugging Only)
⚠️ Important: These manual sync commands are primarily for development, debugging, or emergency situations. In normal workflows, CI automatically handles syncing when you merge changes.
Environment Setup
For local development/debugging, create a .env file in the packages/common directory:
POSTHOG_PROJECT_ID=your-project-id
POSTHOG_API_KEY=your-api-key
POSTHOG_API_HOST=https://eu.posthog.com # Optional, defaults to EU instance
Manual Sync Commands
Run these commands from packages/common (typically only needed for debugging):
# Check sync status (read-only)
npx tsx scripts/sync-early-access-features.ts --check
# Preview changes without applying them
npx tsx scripts/sync-early-access-features.ts --dry-run
# Sync changes to PostHog
npx tsx scripts/sync-early-access-features.ts
# Sync and delete untracked features in PostHog
npx tsx scripts/sync-early-access-features.ts --delete-untracked
Package Scripts
If configured in package.json:
pnpm run sync-early-access-features --check
pnpm run sync-early-access-features --dry-run
pnpm run sync-early-access-features
How It Works
Language Handling
- Declaration: Features are defined with names/descriptions in all supported languages
- PostHog Sync: Only English variants (
name.en,description.en) are sent to PostHog - Frontend Usage: Your app can use any language variant from the declaration
PostHog Integration
When you sync features to PostHog:
- Feature Creation: New features are created with English name/description
- Feature Flag Association: PostHog automatically creates feature flags based on the feature name
- User Opt-in: Users can opt in/out through PostHog's early access management UI
- Override Behavior: User opt-in/out overrides any existing release conditions on the feature flag
Frontend Integration
Use PostHog's JavaScript SDK to implement early access features:
// Get all early access features
posthog.getEarlyAccessFeatures((features) => {
const betaFeatures = features.filter((feature) => feature.stage === 'beta');
const comingSoonFeatures = features.filter((feature) => feature.stage === 'concept');
// Update your UI
});
// Handle user opt-in/out
posthog.updateEarlyAccessFeatureEnrollment('my-new-feature', true); // opt in
posthog.updateEarlyAccessFeatureEnrollment('my-new-feature', false); // opt out
// Check if feature is enabled for current user
const isEnabled = posthog.isFeatureEnabled('my-new-feature');
Example Workflow
- Plan Feature: Decide on feature name, description, and initial stage
- Add Declaration: Define feature in
EARLY_ACCESS_FEATURES - Create Pull Request: Submit your changes for review
- Merge to Main: CI automatically syncs the feature to PostHog when merged
- Implement Frontend: Add PostHog integration to your app
- Iterate: Update stage and descriptions - CI keeps PostHog in sync automatically
🚀 That's it! No manual sync commands needed. CI handles everything when you merge.
Best Practices
Feature Lifecycle
- Start with
conceptfor features in development - Move to
betawhen ready for user testing - Graduate to
general-availabilitywhen stable - Remove declaration when feature becomes permanent
Naming
- Use descriptive, action-oriented names
- Keep names concise but clear
- Avoid technical jargon in user-facing names
Descriptions
- Write clear, benefit-focused descriptions
- Explain what users can expect
- Keep descriptions consistent across languages
Version Control
- Include feature additions in pull requests
- Document feature decisions in commit messages
- Use feature branches for major feature work
Troubleshooting
Common Issues
"Missing feature in PostHog"
- Feature was declared but not synced
- Run sync script to create feature
"Extra feature in PostHog not declared"
- Feature exists in PostHog but not in code
- Either add declaration or use
--delete-untracked
"Name/Description mismatch"
- PostHog has different values than declared
- Run sync to update PostHog with current values
Sync Script Options
--dry-run # Preview changes without applying
--delete-untracked # Remove PostHog features not declared
--check # Only check sync status (read-only)
--help # Show usage information
References
Related Files
src/early_access_features.ts- Feature declarationsscripts/sync-early-access-features.ts- Sync scriptscripts/tsconfig.json- TypeScript configuration for scriptsscripts/README.md- Script-specific documentation