Skip to content

Configuration

Featly is configured through the standard ASP.NET Core configuration pipeline (appsettings.json, environment variables, user secrets) plus, for runtime-editable settings, the database.

Settings resolve in this order, highest wins (ADR-0016):

  1. Hardcoded defaults — sensible defaults baked into the code.
  2. appsettings.json / environment variables — the bootstrap baseline.
  3. Database — overrides both, for settings an operator edits in the dashboard.

Some settings are bootstrap-only and cannot live in the database, because they are read before the database connection exists: the connection string, the AutoMigrate flag, Kestrel URLs, and the bootstrap admin identifier.

Bound from configuration into FeatlyServerOptions.

Key Default Notes
AdminApiKey "" Static bearer key for the admin API + dashboard login. A bootstrap shortcut — prefer minted, user-bound keys. Treat as a secret.
SdkApiKey "" Static bearer key for the SDK API (/api/sdk/*). Treat as a secret.
AutoCreateDefaultProject true Create a default project + environment on first boot.
DefaultProjectKey default Key of the auto-created project.
DefaultEnvironmentKey development Key of the auto-created environment.

Opt-out toggles for entire feature areas (ADR-0024). All default true. Disabling an area drops its HTTP endpoints and removes it from the dashboard nav. See Modularity.

Key Default Notes
Flags true Feature flags.
Configs true Dynamic configuration.
Segments true Reusable audiences.
Experiments true A/B testing + exposure events.
Approvals true Approval workflows / pending changes.
Webhooks true Outbound webhook delivery.
Audit true Audit log.
Rbac true Role management UI/API (the permission checks always run).

Bound into SqliteFeatlyStoreOptions.

Key Default Notes
ConnectionString Data Source=featly.db Any Microsoft.Data.Sqlite connection string. Bootstrap-only.
AutoMigrate true Apply pending EF Core migrations at startup. Set false in production and run featly db migrate from your release pipeline. Bootstrap-only.

Bound into FeatlyAuthorizationOptions. DB-overridable (AutoProvisionMode).

Key Default Notes
BootstrapAdminIdentifier "" When set, the identifier (email / OIDC sub) is treated as admin on first boot and the user row is seeded. Bootstrap-only. An alternative to featly bootstrap-admin.
AutoProvisionMode Open Open: an authenticated user with no role assignment gets the viewer floor. Closed: deny unless an explicit assignment grants access.

Bound into FeatlyAuditOptions. DB-overridable. Controls audit-log retention.

Key Default Notes
RetentionDays 0 0 keeps audit entries forever. A positive value prunes entries older than N days (a background worker prunes every 6 hours).

Bound into FeatlyApprovalDefaultsSettings. DB-overridable. The default approval-policy templates applied to an environment that has no explicit policy — one template for production-like environments (Prod) and one for the rest (NonProd). An environment whose key contains prod uses the Prod template.

Each template (Prod, NonProd) has:

Key Default Notes
Required false Whether mutations require approval.
MinApprovals 1 Number of approvals needed before a change applies.
AuthorCanApproveOwnChange false Whether the proposer may approve their own change.
AllowEmergencyBypass true Whether an audited break-glass bypass is permitted.

Bound into WebhookOptions — the delivery worker’s tuning. DB-overridable.

Key Default Notes
PollInterval 00:00:05 How often the worker drains the delivery queue.
BatchSize 50 Max deliveries claimed per poll.
MaxAttempts 6 Attempts before a delivery is dead-lettered.
BaseRetryDelay 00:00:10 Exponential backoff base (base · 2^(n-1)).
MaxRetryDelay 00:30:00 Backoff cap.
RequestTimeout 00:00:10 Per-delivery HTTP timeout.

Bound into FeatlyTelemetryOptions — server-side OpenTelemetry. Off by default. Config-only (not DB-overridable): the export pipeline is built once at host startup, before the database is reachable.

The Featly meter (Featly.Server) and activity source (Featly.Server) are always present and cost nothing while nothing listens. Enabled controls whether AddFeatlyServerTelemetry(builder.Configuration) wires the OpenTelemetry SDK — ASP.NET Core + HttpClient instrumentation plus the OTLP exporter.

Key Default Notes
Enabled false Master switch. When false, no OpenTelemetry services are registered and there is no per-request overhead.
Traces true Export spans (HTTP server/client + Featly’s featly.change.apply, featly.webhook.deliver) when enabled.
Metrics true Export meters (HTTP + Featly’s custom counters/histograms) when enabled.
ServiceName Featly OpenTelemetry service.name resource attribute.
OtlpEndpoint null OTLP collector URL (e.g. http://localhost:4317). When unset, falls back to OTEL_EXPORTER_OTLP_ENDPOINT and the OpenTelemetry default.
OtlpProtocol Grpc Grpc (port 4317) or HttpProtobuf (port 4318).

Custom metrics emitted by the server:

Instrument Type Tags
featly.server.evaluations counter featly.entity_type (flag/config), featly.reason
featly.server.events_ingested counter featly.event_type (Exposure/Custom)
featly.server.changes_applied counter featly.change_action, featly.bypassed
featly.server.audit_writes counter featly.action
featly.server.webhook_deliveries counter featly.result (success/failure)
featly.server.webhook_delivery_duration histogram (ms) featly.result
{
"Featly": {
"Server": {
"AdminApiKey": "set-via-secret",
"SdkApiKey": "set-via-secret",
"DefaultEnvironmentKey": "production",
"Features": { "Experiments": false }
},
"Storage": { "Sqlite": { "ConnectionString": "Data Source=/var/lib/featly/featly.db", "AutoMigrate": false } },
"Authorization": { "AutoProvisionMode": "Closed" },
"Audit": { "RetentionDays": 90 },
"ApprovalDefaults": { "Prod": { "Required": true, "MinApprovals": 2 } },
"Webhooks": { "MaxAttempts": 8 },
"Telemetry": { "Enabled": true, "OtlpEndpoint": "http://otel-collector:4317" }
}
}

Keep secrets out of source control: use environment variables (Featly__Server__AdminApiKey=...) or a secret store, not committed JSON.

The featly CLI reads these when an explicit option is not passed:

Variable Used by Falls back to
FEATLY_SQLITE featly db * (offline) Data Source=featly.db
FEATLY_SERVER_URL featly apikey / env / export / import / bootstrap-admin http://localhost:5080
FEATLY_API_KEY the online admin commands (not bootstrap-admin) — (required)

The static AdminApiKey / SdkApiKey are bootstrap shortcuts. For real, auditable identities, mint keys bound to a user:

Terminal window
featly apikey generate --name ci --user you@example.com --scope AdminWrite

A user-bound key authenticates over Authorization: Bearer and acts as that user, so RBAC, the audit log, and approvals attribute the action to a real person. See ADR-0023.