Deploy feature flags, percentage rollouts, and multi-environment configuration management on your own infrastructure. No SaaS. No vendor lock-in.
AtlasFlag is a self-hosted feature flag and configuration management platform built with Spring Boot and PostgreSQL. It gives engineering teams full control over feature releases without depending on third-party services.
Use it to:
- Decouple deploys from releases — ship code dark, turn it on when ready
- Run percentage rollouts — expose a feature to 5% of users before full rollout
- Manage per-environment flags — different states for
DEVELOPMENT,STAGING,PRODUCTION - Kill-switch bad features instantly — toggle a flag off without a redeploy
- Audit every change — full immutable audit trail with before/after values
Feature flag management UI — create, toggle, and roll out flags across environments
Immutable audit trail — every change recorded with user, timestamp, and diff
| Feature | Details |
|---|---|
| Boolean flags | Enabled/disabled with optional default value |
| Percentage rollouts | Deterministic, hash-based — same user always gets the same result |
| User attribute targeting | AND/OR rules on caller-supplied attributes (plan, country, email, etc.) |
| Remote configuration | STRING, NUMBER, JSON flag types — change config values without deploys |
| Multi-environment | DEVELOPMENT, STAGING, PRODUCTION with independent states |
| Environment promotion | One-click promote flag config to the next environment |
| Instant toggles | No cache invalidation delay — flags flip in under 100ms |
| SSE streaming | SDK cache updated in real-time via Server-Sent Events — no polling |
| Evaluation analytics | Per-flag hourly evaluation counts with true/false breakdown |
| Flag search | Filter flags by key as you type |
| Webhooks | HTTP notifications on every flag change, HMAC-SHA256 signed |
| In-memory cache | Caffeine-backed, zero external dependencies |
| Audit logging | Every change logged with before/after JSON |
| Role-based access | ADMIN · USER · VIEWER — enforced via JWT claims |
| User management | Create, edit, delete users and change passwords — UI + API (ADMIN only) |
| Java SDK | Bulk evaluation, local caching, SSE live updates, typed remote config, never throws |
| Bulk evaluation | Evaluate up to 100 flags in a single HTTP call |
| Web UI | Built-in dashboard — flags, audit logs, webhooks, analytics |
| REST API | Clean, versioned REST API (/api/v1/...) |
| Self-hosted | Your data stays in your database |
| Single-service deploy | Backend serves the dashboard — one deployment is all you need |
- Backend: Java 21 · Spring Boot 3.2 · Spring Security (JWT) · Spring Data JPA
- Database: PostgreSQL 16 · Flyway migrations
- Cache: Caffeine (in-memory) — no external cache server required
- Frontend: Vanilla JS · Tailwind CSS · Thymeleaf templates
- SDK: Java · OkHttp · Caffeine
- Deploy: Any Docker-compatible host — one service serves both dashboard and API
Prerequisites: Java 21, Docker
# 1. Start PostgreSQL
cd infra && docker-compose up -d && cd ..
# 2. Run the service
./gradlew :atlas-flag-service:bootRun
# 3. Open the dashboard
open http://localhost:8080
# Login: admin / admin123See DEPLOYMENT.md for the full guide. TL;DR:
- Database: Provision a PostgreSQL instance — grab the JDBC connection string
- Service: Build the Docker image (
docker build -t atlasflag .) and deploy — set the required env vars - Open
https://your-host/dashboard— the Spring Boot app serves everything
All endpoints require Authorization: Bearer <token> except /api/v1/auth/login and /api/v1/flags/evaluate.
# Login — returns JWT token
curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "admin123"}'{
"token": "eyJ...",
"type": "Bearer",
"username": "admin",
"role": "ADMIN"
}TOKEN="eyJ..."
# Create a flag
curl -X POST http://localhost:8080/api/v1/flags \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"flagKey": "new-checkout",
"name": "New Checkout Flow",
"environment": "DEVELOPMENT",
"enabled": true,
"rolloutPercentage": 10,
"defaultValue": false
}'
# List flags in an environment
curl "http://localhost:8080/api/v1/flags?environment=PRODUCTION" \
-H "Authorization: Bearer $TOKEN"
# Toggle a flag on/off
curl -X POST "http://localhost:8080/api/v1/flags/new-checkout/toggle?environment=DEVELOPMENT" \
-H "Authorization: Bearer $TOKEN"
# Evaluate a flag (public — no auth required)
curl -X POST http://localhost:8080/api/v1/flags/evaluate \
-H "Content-Type: application/json" \
-d '{"flagKey": "new-checkout", "environment": "PRODUCTION", "userId": "user-42"}'# All changes to a specific flag
curl "http://localhost:8080/api/v1/audit/entity/FeatureFlag/1" \
-H "Authorization: Bearer $TOKEN"
# All changes made by a user
curl "http://localhost:8080/api/v1/audit/user/admin" \
-H "Authorization: Bearer $TOKEN"Full API reference → DETAILED.md
The starter auto-configures AtlasFlagClient from application.properties and adds @FeatureFlag annotation support. No boilerplate required.
Build from source and publish to your local Maven repository:
./gradlew :atlas-flag-spring-boot-starter:publishToMavenLocal// build.gradle
dependencies {
implementation 'com.atlasflag:atlas-flag-spring-boot-starter:1.0.0-SNAPSHOT'
implementation 'org.springframework.boot:spring-boot-starter-aop' // for @FeatureFlag
}# application.yml
atlasflag:
base-url: https://your-atlasflag-host.com
environment: PRODUCTION
cache:
ttl-seconds: 60@Service
public class CheckoutService {
// Method is skipped (returns null) when "new-checkout" flag is disabled
@FeatureFlag("new-checkout")
public CheckoutResult runNewFlow(Order order) { ... }
// Custom default and environment override
@FeatureFlag(value = "beta-pricing", defaultValue = true, environment = "STAGING")
public PricingResult computePrice(String userId) { ... }
}// Or inject AtlasFlagClient directly for full control
@Autowired AtlasFlagClient flags;
boolean enabled = flags.isEnabled("dark-mode", userId, false);
Map<String, Boolean> bulk = flags.isEnabledBulk(List.of("flag-a", "flag-b"), userId, false);// Bean only created when "experimental-cache" flag is enabled at startup
@Bean
@ConditionalOnFeatureFlag("experimental-cache")
public CacheManager experimentalCache() { ... }userId resolution: By default, the starter reads the current user from Spring Security's SecurityContext. Override by registering your own UserIdProvider bean.
The raw SDK (without Spring Boot auto-configuration). Build from source:
./gradlew :atlas-flag-sdk-java:publishToMavenLocal// build.gradle
dependencies {
implementation 'com.atlasflag:atlas-flag-sdk-java:1.0.0-SNAPSHOT'
}AtlasFlagClient client = new AtlasFlagClient.Builder()
.baseUrl("https://your-atlasflag-host.com")
.environment("PRODUCTION")
.cacheTtlSeconds(60) // evaluated values cached locally for 60s
.build();
// Never throws — returns defaultValue if service is unreachable
boolean showNewUI = client.isEnabled("new-checkout", "user-42", false);
client.shutdown(); // call when your app shuts downThe SDK caches evaluated results locally (Caffeine) and refreshes them in the background before they expire. If the service is unreachable, it serves stale cached values and falls back to defaultValue only as a last resort.
Browser / SDK Clients
│
▼
┌──────────────────────────────┐
│ Spring Boot Service (8080) │
│ ┌────────────┐ ┌────────┐ │
│ │ REST API │ │ Web UI │ │
│ └─────┬──────┘ └────────┘ │
│ │ │
│ ┌─────▼──────────────────┐ │
│ │ Feature Flag Service │ │
│ │ + Caffeine Cache │ │
│ └─────┬──────────────────┘ │
└────────┼─────────────────────┘
│
▼
PostgreSQL 16
(flags · users · audit_logs)
Evaluation path: GET /flags/evaluate → cache lookup → DB read on miss → cache write → response. Typical p99 < 5ms when cached.
Full architecture → DETAILED.md
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
Yes | jdbc:postgresql://localhost:5432/atlasflag |
PostgreSQL JDBC URL |
DATABASE_USERNAME |
Yes | atlasflag |
DB username |
DATABASE_PASSWORD |
Yes | atlasflag |
DB password |
JWT_SECRET |
Yes in prod | dev default | Min 32 chars · change in production |
CORS_ALLOWED_ORIGINS |
Prod | localhost | Comma-separated allowed origins |
PORT |
No | 8080 |
HTTP port |
DB_POOL_SIZE |
No | 5 |
HikariCP max connections |
DB_SSL_MODE |
No | prefer |
Set to require for cloud PostgreSQL providers |
The service seeds an admin user on first startup:
| Field | Value |
|---|---|
| Username | admin |
| Password | admin123 |
| Role | ADMIN |
Change this password immediately in production.
atlas-flag/
├── service/ # Spring Boot backend
│ ├── src/main/java/ # Application code
│ ├── src/main/resources/
│ │ ├── templates/ # Thymeleaf HTML (dashboard, login)
│ │ ├── static/js/app.js # Frontend JS
│ │ └── db/migration/ # Flyway SQL migrations
│ └── build.gradle
├── sdk-java/ # Java client SDK
├── infra/
│ └── docker-compose.yml # PostgreSQL for local dev
├── CLAUDE.md # AI assistant context + project commands
├── DETAILED.md # Full technical documentation
├── QUICKSTART.md # 5-minute setup guide
└── SETUP.md # Java environment setup
- Boolean flags with percentage rollouts
- Multi-environment flag management (DEVELOPMENT → STAGING → PRODUCTION)
- Environment promotion (one-click copy flag config to next environment)
- Flag search / filter
- Java SDK — bulk evaluation, local caching, background refresh
- Bulk evaluate endpoint (
POST /api/v1/flags/evaluate/bulk) - Webhook notifications on flag change (HMAC-SHA256 signed)
- Immutable audit trail
- JWT authentication + RBAC (ADMIN · USER · VIEWER)
- User management API
- User management UI (create, edit, delete users, change passwords)
- Web UI dashboard (flags · audit logs · webhooks)
- Caffeine in-memory cache (no Redis needed)
- User attribute targeting (AND/OR rules, 11 operators)
- Remote configuration (STRING/NUMBER/JSON flag types)
- Evaluation analytics (hourly counters, 24h dashboard view)
- SSE streaming (SDK cache updated in real-time)
- Approval workflows
- Scheduled flag changes
- Python / Node.js / Go SDKs
- A/B testing integration
Bug reports, feature requests, and pull requests are welcome. See CONTRIBUTING.md for development setup, code conventions, and the PR process.
MIT — see LICENSE
Topics: feature-flags feature-toggles spring-boot java postgresql self-hosted rest-api feature-management sdk rollout jwt open-source