FeaturOne 1.0.0
dotnet add package FeaturOne --version 1.0.0
NuGet\Install-Package FeaturOne -Version 1.0.0
<PackageReference Include="FeaturOne" Version="1.0.0" />
<PackageVersion Include="FeaturOne" Version="1.0.0" />
<PackageReference Include="FeaturOne" />
paket add FeaturOne --version 1.0.0
#r "nuget: FeaturOne, 1.0.0"
#:package FeaturOne@1.0.0
#addin nuget:?package=FeaturOne&version=1.0.0
#tool nuget:?package=FeaturOne&version=1.0.0
FeaturOne
Internal feature flags for .NET applications: a SQL table as the source of truth, overlays from appsettings.json and environment variables, plus sticky canary rollouts.
The package is evaluation-only. Applications create the table, manage rows themselves, and call IFeatureFlagService.IsEnabled.
Install
dotnet add package FeaturOne
Then run the script that matches your database (also packed under scripts/ in the NuGet package):
Configuration
Add a FeatureFlags section. ASP.NET Core already applies environment variables on top of JSON, so FeatureFlags__Flags__NewCheckout__Enabled=true wins over appsettings.json.
{
"FeatureFlags": {
"ConnectionString": "Server=.;Database=App;Trusted_Connection=True;TrustServerCertificate=True;",
"TableName": "FeatureFlags",
"SqlDialect": "SqlServer",
"RefreshInterval": "00:00:30",
"Flags": {
"NewCheckout": {
"Enabled": true,
"RolloutMode": "Canary",
"CanaryStartAt": "2026-08-18T00:00:00Z",
"CanaryDuration": "1.00:00:00",
"PinProperty": "user.id"
},
"LegacyReport": {
"Enabled": false
}
}
}
}
CanaryDuration uses .NET TimeSpan text (1.00:00:00 = 24 hours).
Precedence (per property)
- Environment variables
appsettings.json(FeatureFlags:Flags:<name>)FeatureFlagstable
A flag may exist only in configuration. If the database is unreachable, FeaturOne keeps the last successful table snapshot, applies configuration on top, and logs a warning. An unknown flag is off.
Registration
The package does not take a SQL provider dependency. The host supplies a connection factory:
builder.Services.AddFeaturOne(builder.Configuration, options =>
{
options.ConnectionFactory = () => new SqlConnection(options.ConnectionString);
// options.SqlDialect = FeaturOneSqlDialect.PostgreSql;
});
Without ConnectionFactory, only configuration and environment flags are evaluated.
Evaluation
public sealed class CheckoutService(IFeatureFlagService flags)
{
public async Task<IResult> HandleAsync(User user)
{
var context = new FeatureContext
{
["user.id"] = user.Id.ToString()
};
if (await flags.IsEnabledAsync("NewCheckout", context))
{
return Results.Ok("canary path");
}
return Results.Ok("stable path");
}
}
Instant flags do not need a context. Canary flags fail closed when PinProperty is missing on the flag or the value is missing from FeatureContext.
States and rollout
Enabled |
RolloutMode |
Result |
|---|---|---|
false |
any | Always off |
true |
Instant |
Always on |
true |
Canary |
Linear ramp from 0% to 100% between CanaryStartAt and CanaryStartAt + CanaryDuration |
Before the start instant the canary is 0%. After the window it is 100%.
Sticky pinning
The bucket is SHA256(flagName + pinProperty + pinValue) mapped to 0..9999. The same subject stays in the same bucket for the life of the flag. As the percentage increases the included set is monotonic: once a subject is in, it stays in.
PinProperty is configurable per flag (user.id, tournament.code, …). Use that exact key in FeatureContext.
Table
| Column | Meaning |
|---|---|
Name |
Primary key |
Enabled |
Master switch |
RolloutMode |
Instant or Canary |
CanaryStartAt |
Ramp start (UTC) |
CanaryDuration |
.NET TimeSpan text |
PinProperty |
Context key used for pinning |
UpdatedAt |
Audit only, not read by the package |
TableName must be a simple identifier (FeatureFlags, not dbo.FeatureFlags). Set the default schema on the connection or use a synonym if you need a different schema.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Dapper (>= 2.1.66)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 251 | 8/18/2026 |