Overview
NuGet.Services.FeatureFlags is the core library for runtime feature control across NuGet.org services. It separates flag evaluation from flag persistence, providing a thin client that reads from an in-memory cache while a background refresh loop keeps the cache synchronized with the authoritative state stored externally (in practice, a JSON file in Azure Blob Storage). This means flag checks are always synchronous and allocation-free at call time — there are no async waits or I/O on the hot path.
The library distinguishes between two kinds of toggles. Features are binary on/off switches applicable to the entire system — for example, disabling package uploads when ingestion is degraded. Flights are targeted rollouts that can be enabled for a defined subset of users identified by username, email domain, or site-admin status, or for all users at once. This makes it possible to gradually expose new behavior to administrators or early-access testers without shipping separate code paths for each audience.
The project targets both net472 and netstandard2.0, keeping it compatible with the legacy ASP.NET MVC gallery and with modern .NET Standard-based jobs and validation services. Its only external dependency is Microsoft.Extensions.Logging, which it uses exclusively for diagnostic output when flags are missing or the cache has not yet been loaded.
Role in System
IFeatureFlagStorageService is the only extension point it exposes. The gallery implements FeatureFlagFileStorageService (read-only) and EditableFeatureFlagFileStorageService (adds ETag-based save and user-removal) in NuGetGallery.Core. Jobs that consume flags register their own storage implementations.
In-Memory Cache
All flag state is held in a single
FeatureFlags object stored in a private field on FeatureFlagCacheService. Reads are lock-free field reads; writes replace the field atomically. No per-request I/O.Targeted Flights
Flight supports four targeting axes: all users, site admins, a list of explicit usernames, and a list of email domains. All comparisons are case-insensitive. The All property short-circuits every other check when true.Graceful Degradation
When the cache is empty or a flag name is unknown,
IsEnabled returns the caller-supplied defaultValue rather than throwing, and emits a structured log entry at LogError or LogWarning level for observability.Staleness Telemetry
After each refresh attempt,
FeatureFlagCacheService reports the elapsed time since the last successful load to the optional IFeatureFlagTelemetryService. If flags have never loaded, it reports TimeSpan.MaxValue.Key Files and Classes
Dependencies
NuGet Package References
Internal Project References
This project has no internal project references. It is consumed by other projects in the solution.Notable Patterns and Implementation Details
FeatureFlagCacheService accepts a Func<IFeatureFlagStorageService> factory rather than a direct IFeatureFlagStorageService instance. This allows the DI container (Autofac, in the gallery) to resolve a new storage instance on each refresh cycle — important when the storage service itself holds scoped resources such as HTTP clients or Azure SDK clients.RefreshAsync is intended to be called once at application startup before the background loop begins, ensuring that all flag checks after initialization have a valid cache. The interface’s XML doc explicitly calls this out: “This should be called at app startup to guarantee feature flags have been loaded.”All feature and flight name lookups use
OrdinalIgnoreCase dictionaries constructed at FeatureFlags creation time. This means the FeatureFlagClient performs a single dictionary lookup per call with no string allocation for case normalization.Feature flag state is serialized as a JSON file in Azure Blob Storage and managed through the NuGet.org admin panel. The
NuGetGallery.Core project provides EditableFeatureFlagFileStorageService, which adds ETag-based optimistic concurrency for saves and a RemoveUserAsync method for GDPR-style user data removal from flight allowlists.