Run Flaggr on your own infrastructure. The platform's source isn't public, so self-hosting is available on request.
Last updated October 25, 2026
Self-Hosting
Most teams use the hosted service at flaggr.dev. Flaggr's source code isn't public and there's no public container image, so self-hosting is available on request: email hello@flaggr.dev and say where you want to run it.
Flaggr's platform source and container images aren't on GitHub or ghcr.io. Its GitHub organization, flaggr-dev, holds only the SDKs, the CLI and the Terraform provider, and the flaggr account on GitHub isn't Flaggr's. Don't run an image or use a repository from there that claims to be Flaggr. See official sources.
Your applications don't change: @flaggr/sdk takes the deployment's base URL as apiUrl, the MCP server reads it from FLAGGR_API_URL, and any OpenFeature SDK evaluates flags through OFREP.
What a deployment needs
Flaggr is a Next.js app. One deployment serves the dashboard, the REST, OFREP and Connect APIs, and the SSE streams. It runs next to:
| Component | Used for |
|---|---|
| Postgres | Flags, projects, audit logs and versions. Without DATABASE_URL the app falls back to file storage, which is for development only |
| Firebase Authentication | Dashboard sign-in |
| Redis | The shared cache and real-time pub/sub between instances (REDIS_URL). A KV REST store (KV_REST_API_URL and KV_REST_API_TOKEN, such as Upstash Redis) can hold the cache, but pub/sub needs Redis. Required when you run more than one instance |
| Upstash Redis (optional) | Rate limits shared across instances. Without it, each instance limits on its own |
| Resend (optional) | Email notifications |
Environment Variables
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | Yes | Pooled Postgres connection string for app queries |
DATABASE_URL_DIRECT | Recommended | Direct Postgres connection for migrations (falls back to DATABASE_URL_UNPOOLED, then DATABASE_URL) |
FIREBASE_PROJECT_ID | Yes | Firebase project ID |
FIREBASE_CLIENT_EMAIL | Yes | Service account email |
FIREBASE_PRIVATE_KEY | Yes | Service account private key |
NEXT_PUBLIC_FIREBASE_API_KEY | Yes | Firebase client API key |
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN | Yes | Firebase auth domain |
NEXT_PUBLIC_FIREBASE_PROJECT_ID | Yes | Firebase project ID (client) |
REDIS_URL, or KV_REST_API_URL with KV_REST_API_TOKEN | Recommended (required for multi-instance) | Shared cache: credential, identity and SSO entries reach every instance within ~10 s of a revocation; without it each instance caches them for at most 30 s, and in production /api/health reports cache.shared: false with a cache.warning |
UPSTASH_REDIS_REST_URL | Recommended | Upstash Redis REST endpoint for rate limiting (only) |
UPSTASH_REDIS_REST_TOKEN | Recommended | Redis auth token |
ANALYTICS_CLIENT_HASH_SECRET | Recommended | 32 random bytes as hex. Keys the daily client hash (data._c) on SDK telemetry and mobile analytics rows; without it, rollout RUM checks can't cap one client's sessions |
RESEND_API_KEY | Optional | Email notifications |
RESEND_FROM_EMAIL | Optional | From address for emails |
The Deployment guide lists the rest of the optional settings.
Always trim environment variables when passing them via deployment configs. Trailing whitespace in URLs causes cryptic connection failures.
Health Checks
| Endpoint | Use it for |
|---|---|
/api/healthz | Liveness and readiness probes: 200 while the process serves HTTP. It doesn't check dependencies |
/api/readyz | Monitoring and alerting: 200 when storage (Postgres SELECT 1 within 3 s, or the data/ directory without DATABASE_URL) and the read cache work, 503 otherwise. Each instance reuses its Postgres answer for 5 s |
/api/health | Status details: version, the cache and storage backends, and whether instances share a cache (cache.shared) |
Don't use /api/readyz as a readiness probe: every replica shares the database, so a Postgres outage would take every replica out of the Service at once, including the flag reads the cache could still serve. A monitor that polls it more often than Neon's suspend timeout keeps the Neon compute awake (at most one SELECT 1 per instance every 5 seconds).
curl -s https://your-flaggr-host/api/health | jq '{status, storage: .storage.backend, cache: .cache.backend, shared: .cache.shared}'
# { "status": "healthy", "storage": "postgres", "cache": "redis", "shared": true }cache.backend is the write plane's, which holds credentials; cache.readCache.backend and cache.writeCache.backend give each plane's own.
Performance Tuning
- Replicas: Start with 2 replicas for high availability, and size them by load-testing your own traffic.
- Redis: Strongly recommended for production. Without Redis, each serverless instance has its own in-memory cache (no sharing).
- Cold starts: Keep at least one instance warm (for example, min-instances=1 on Cloud Run) so the first requests after idle don't wait for a cold start.