Skip to main content

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.

No official platform image or repository on GitHub

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:

ComponentUsed for
PostgresFlags, projects, audit logs and versions. Without DATABASE_URL the app falls back to file storage, which is for development only
Firebase AuthenticationDashboard sign-in
RedisThe 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

VariableRequiredDescription
DATABASE_URLYesPooled Postgres connection string for app queries
DATABASE_URL_DIRECTRecommendedDirect Postgres connection for migrations (falls back to DATABASE_URL_UNPOOLED, then DATABASE_URL)
FIREBASE_PROJECT_IDYesFirebase project ID
FIREBASE_CLIENT_EMAILYesService account email
FIREBASE_PRIVATE_KEYYesService account private key
NEXT_PUBLIC_FIREBASE_API_KEYYesFirebase client API key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAINYesFirebase auth domain
NEXT_PUBLIC_FIREBASE_PROJECT_IDYesFirebase project ID (client)
REDIS_URL, or KV_REST_API_URL with KV_REST_API_TOKENRecommended (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_URLRecommendedUpstash Redis REST endpoint for rate limiting (only)
UPSTASH_REDIS_REST_TOKENRecommendedRedis auth token
ANALYTICS_CLIENT_HASH_SECRETRecommended32 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_KEYOptionalEmail notifications
RESEND_FROM_EMAILOptionalFrom address for emails

The Deployment guide lists the rest of the optional settings.

Warning

Always trim environment variables when passing them via deployment configs. Trailing whitespace in URLs causes cryptic connection failures.

Health Checks

EndpointUse it for
/api/healthzLiveness and readiness probes: 200 while the process serves HTTP. It doesn't check dependencies
/api/readyzMonitoring 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/healthStatus 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.