AutoGPT Feature Flag System: How Gradual Rollouts Work with LaunchDarkly
AutoGPT implements a comprehensive feature flag system using LaunchDarkly to enable gradual rollouts, with backend decorators and frontend React wrappers that evaluate flags per-request and stream real-time updates to users.
The feature flag system in the Significant-Gravitas/AutoGPT repository allows developers to safely release functionality to specific user cohorts without deploying new code. Built on LaunchDarkly's SDK, the architecture spans both the FastAPI backend and the Next.js frontend, providing immediate toggles that default to safe fallback values when the service is unavailable.
Backend Architecture and Flag Enum
The backend implementation centers on a single source of truth for all flag keys defined in autogpt_platform/backend/backend/util/feature_flag.py. This file contains the Flag enum, which guarantees consistency across the application by centralizing every LaunchDarkly key identifier.
LaunchDarkly Client Lifecycle
The system manages the LaunchDarkly client through explicit lifecycle functions: initialize_launchdarkly(), get_client(), and shutdown_launchdarkly(). These utilities implement a singleton pattern with lazy initialization, ensuring the client starts only when first needed and shuts down gracefully during application termination.
If the SDK key (settings.secrets.launch_darkly_sdk_key) is missing or the client fails to initialize, the system operates in degraded mode, automatically returning the default value supplied to any flag check—typically False to keep features disabled.
User Context and Targeting
For precise gradual rollouts, the system builds rich user contexts via _fetch_user_context_data(). This function queries Supabase to enrich the LaunchDarkly context with attributes including user role, email, domain, and anonymity status. To avoid repeated database calls, the context is cached for 24 hours per user.
Flag evaluation occurs through is_feature_enabled(flag, user_id, default), which returns a boolean, or get_feature_flag_value() for raw flag data (including string or numeric variations). When LaunchDarkly evaluates a flag, it checks if the user's context matches the current rollout percentage or targeting rules defined in the LaunchDarkly dashboard.
Route Protection and Dependencies
The system offers two declarative approaches to protect FastAPI endpoints:
feature_flag()decorator – Wraps route handlers to check the flag before execution. If disabled, it raisesHTTPException(status_code=404).create_feature_flag_dependency()– A factory function that returns a FastAPIDepends()callable, allowing entire routers to require a specific flag.
Both methods evaluate the flag per request, meaning changes to rollout percentages in the LaunchDarkly UI take effect instantly for subsequent API calls without requiring a server restart.
Frontend Implementation with React
The frontend leverages launchdarkly-react-client-sdk to stream flag states to the browser in real time.
Higher-Order Component Pattern
The withFeatureFlag higher-order component, located in autogpt_platform/frontend/src/services/feature-flags/with-feature-flag.tsx, provides declarative UI gating. It wraps any React component and automatically redirects to /404 when the specified flag is disabled.
// Usage in a Next.js page
import { withFeatureFlag } from "@/services/feature-flags/with-feature-flag";
import ChatPage from "./ChatPage";
export default withFeatureFlag(ChatPage, "chat");
The HOC waits for hasFlagLoaded to prevent flickering, then checks flags["chat"] from the useFlags() hook. Because LaunchDarkly pushes updates over a WebSocket connection, users see features appear or disappear instantly when rollout percentages change.
Direct Flag Checks
Components can also access flags directly for conditional rendering:
import { useFlags } from "launchdarkly-react-client-sdk";
export function NewUI() {
const flags = useFlags();
if (!flags["beta-blocks"]) return null;
return <div>Experimental UI</div>;
}
Gradual Rollout Execution Flow
The feature flag system enables safe, staged releases through the following automated flow:
- Configuration – The application initializes the LaunchDarkly client using the SDK key from environment secrets.
- User Identification – When a protected endpoint receives traffic, the system extracts the
user_idfrom the JWT and constructs a cached LaunchDarkly Context containing Supabase user attributes. - Evaluation – LaunchDarkly compares the user's context against active rollout rules (percentage rollouts, role-based targeting, or email domain lists).
- Decision – The system returns
TrueorFalse. IfFalse, the backend returns HTTP 404 or the frontend redirects to the 404 page. - Real-time Updates – Changing a flag's rollout percentage in the LaunchDarkly dashboard immediately affects new requests and streams updates to open browser sessions.
Testing and Mobile Considerations
For unit testing, the mock_flag_variation context manager allows developers to temporarily override flag values without a LaunchDarkly connection:
from backend.util.feature_flag import mock_flag_variation
async def test_chat_disabled(client):
with mock_flag_variation("chat", False):
response = await client.get("/chat", headers=auth_header)
assert response.status_code == 404
The classic mobile client uses a different approach. Located in classic/frontend/lib/utils/feature_flags.dart, the mobile implementation relies on static compile-time constants like userExperienceIterationTwoEnabled. These require a new app build to change, meaning mobile rollouts are manual rather than dynamic, with most feature gating deferred to backend flag evaluation.
Summary
- The feature flag system uses a centralized
Flagenum infeature_flag.pyto ensure backend and frontend use identical keys. - LaunchDarkly contexts are enriched with Supabase user data and cached for 24 hours to optimize performance while enabling sophisticated targeting.
- Backend routes are protected via decorators or FastAPI dependencies that return HTTP 404 when flags are disabled.
- The React frontend streams flag states via WebSocket, allowing
withFeatureFlagto hide or show UI instantly as rollout percentages change. - Graceful degradation ensures features remain disabled if LaunchDarkly is unavailable, and
mock_flag_variationfacilitates testing without external service dependencies.
Frequently Asked Questions
How does AutoGPT handle feature flag evaluation if LaunchDarkly is offline?
If the LaunchDarkly client fails to initialize or the SDK key is missing, the system falls back to the default value provided to is_feature_enabled(). Typically set to False, this ensures features stay disabled safely rather than causing application errors or exposing unfinished functionality.
Can I target specific user groups for gradual rollouts instead of random percentages?
Yes. The _fetch_user_context_data() function pulls role, email domain, and other attributes from Supabase into the LaunchDarkly context. This allows you to configure rules in the LaunchDarkly dashboard targeting specific user cohorts, such as beta testers or internal staff, while maintaining random percentage rollouts for general users.
Why does the backend use HTTP 404 when a feature flag is disabled?
The feature_flag decorator and dependency factory raise HTTPException(status_code=404) to maintain security through obscurity. Returning a 404 rather than 403 or a "feature disabled" message prevents attackers from discovering hidden endpoints and makes disabled features indistinguishable from non-existent routes.
How do I test code that depends on a feature flag being enabled?
Use the mock_flag_variation context manager in your test suite. This utility temporarily overrides the flag value for the duration of the test context, allowing you to verify both enabled and disabled states without requiring a live LaunchDarkly connection or modifying environment variables.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →