A lightweight Feature Flags App built with Python (Flask), MongoDB and a frontend using HTML, CSS, and JavaScript.
This app lets you create, update, toggle, and delete feature flags across multiple environments (development, staging, production).
This project is split into three repositories, each with a specific role in the deployment and delivery workflow:
-
Application Repository (feature-flags-app) <--Current Repo
- Contains the Feature Flags API & UI
- Contains the GitHub Actions workflows to build the feature-flags-app image & sync frontend s3 bucket
-
Infrastructure Repository (feature-flags-infrastructure)
- Contains Terraform code for provisioning the required AWS resources (VPC, EKS, S3, CloudFront, Route53, etc.).
- Contains the GitHub Actions workflow to apply the terraform
-
Resources Repository (feature-flags-resources)
- Holds Helm charts and Argo CD Applications that define the Kubernetes manifests.
- Implements GitOps: Argo CD watches this repo and syncs changes to the EKS cluster.
This GitHub Actions workflow automates testing, versioning, and publishing of the Feature Flags API Docker image to AWS Elastic Container Registry (ECR) & GitHub Container Registry (GHCR).
This workflow detects changes in frontend dir (on push to /frontend) and syncs the changes to the s3 bucket that holds those static files.
To run these workflows, configure the following secrets and variables in your GitHub repository settings.
Navigate to Settings → Secrets and variables → Actions → Repository secrets:
| Secret Name | Description | Used In |
|---|---|---|
OIDC_AWS_ROLE_ARN |
AWS IAM role ARN for OIDC authentication | feature-flags-ci-cd.yaml, s3-frontend-sync.yaml |
Note: GITHUB_TOKEN is automatically provided by GitHub Actions and doesn't need manual configuration.
Navigate to Settings → Secrets and variables → Actions → Repository variables:
| Variable Name | Description | Example Value | Used In |
|---|---|---|---|
AWS_REGION |
AWS region where resources are deployed | ap-south-1 |
feature-flags-ci-cd.yaml, s3-frontend-sync.yaml |
ECR_REGISTRY |
AWS ECR registry URL | 888432181118.dkr.ecr.ap-south-1.amazonaws.com |
feature-flags-ci-cd.yaml |
ECR_REPO |
ECR repository name | feature-flags-api |
feature-flags-ci-cd.yaml |
S3_FRONTEND_BUCKET_URL |
S3 bucket URL for frontend files | s3://your-bucket-name |
s3-frontend-sync.yaml |
Both workflows use AWS OIDC for authentication.
Create the oidc using terraform from /oidc directory in feature-flags-infrastructure repo
Or create it manually - for more details on setting up AWS OIDC with GitHub Actions, see the AWS documentation.
API:
- Acts as the core API server for managing feature flags.
- Provides endpoints for creating, updating, toggling, and deleting feature flags.
- Includes environment-specific configurations for
dev,staging,prod.
MongoDB:
- Serves as the persistent storage for feature flags.
Frontend:
- Static, Stored in S3 and served via CloudFront.
The application comes with pre-configured dashboards (available in the feature-flags-resources Repository) to provide immediate insight into the application health.
The Grafana dashboard monitors the Feature Flags API by combining Flask application metrics with Kubernetes resource statistics to visualize traffic, performance, and system health. It tracks critical indicators such as HTTP request rates, 5xx error spikes, and p95 response latency, alongside pod CPU and memory usage to ensure optimal application stability.
The Kibana dashboard provides a centralized view of log data to track high-level log volume, service activity, and error trends. It highlights 5xx errors and application exceptions, offering breakdowns by service to help identify noisy components and analyze error distributions across the infrastructure.
The docker-compose.yml file orchestrates the following services:
-
app (Flask API):
- Runs the Flask application inside a Python-based Docker container.
- Exposes port
5000internally for communication with Nginx. - Connects to MongoDB for persistence.
-
Mongodb:
- Stores feature flag configurations.
- Runs on port 27017 inside the container.
- Persists data on a mounted Docker volume (db-data).
-
Nginx:
- Acts as a reverse proxy for the Flask API.
- Listens on port 80 of the host for external access.
- Routes incoming requests to the Flask backend on port 5000.
- Serves the static UI assets (index.html, app.js)
-
Networks:
- app-network: Connects Nginx ↔ API.
- db-network: Connects API ↔ MongoDB.
-
Volumes:
- db-data: Ensures MongoDB data is persisted across container restarts.
- Config mounts (./nginx.conf, ./static, ./templates) are shared with the Nginx service for configuration and static asset serving.
git clone https://github.com/shaarron/feature-flags-app.git
cd feature-flags-app
# Create environment file (optional - defaults will be used if not provided)
cat > .env << EOF
MONGO_INITDB_ROOT_USERNAME=
MONGO_INITDB_ROOT_PASSWORD=
EOF
# Start all services
docker compose -f docker-compose.local.yaml up -dThe application will be available at:
- Web Interface: http://localhost
- API: http://localhost/flags
- MongoDB: localhost:27017
git clone https://github.com/shaarron/feature-flags-app.git
cd feature-flags-app
# Create and activate virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Run the application
python app.pyThe application will be available at http://localhost:5000
POST /flags
{
"name": "dark-mode",
"description": "Enable dark theme for all users",
"environments": {
"development": true,
"staging": true,
"production": false
}
}**Response (201) **
{
"_id": "abc123",
"name": "dark-mode",
"description": "Enable dark theme for all users",
"environments": {...}
}GET /flags?environment=staging
Retrieves all feature flags, with an enabled field for the selected environment.
Response
[
{
"_id": "abc123",
"name": "dark-mode",
"description": "Enable dark theme for all users",
"environments": {...},
"enabled": true
}
]GET /flags/<id>
Fetches a specific feature flag by ID.
Response
{
"_id": "abc123",
"name": "dark-mode",
"description": "Enable dark theme for all users",
"environments": {...}
}PUT /flags/<id>
Updates name, description, or environment states.
Request Body (partial update allowed):
{
"description": "Enable dark mode toggle for users"
}Response
{
"_id": "abc123",
"name": "dark-mode",
"description": "Enable dark mode toggle for users",
"environments": {...}
}DELETE /flags/<id>
Deletes a feature flag.
Response (204):
{
"message": "Feature flag deleted"
}POST /flags/<id>/toggle
Toggles a flag’s enabled state in a given environment.
Request Body:
{
"environment": "production"
}Response (200)
{
"_id": "abc123",
"name": "dark-mode",
"enabled": true
}

