FriendlyEnvars 1.1.0
dotnet add package FriendlyEnvars --version 1.1.0
NuGet\Install-Package FriendlyEnvars -Version 1.1.0
<PackageReference Include="FriendlyEnvars" Version="1.1.0" />
<PackageVersion Include="FriendlyEnvars" Version="1.1.0" />
<PackageReference Include="FriendlyEnvars" />
paket add FriendlyEnvars --version 1.1.0
#r "nuget: FriendlyEnvars, 1.1.0"
#:package FriendlyEnvars@1.1.0
#addin nuget:?package=FriendlyEnvars&version=1.1.0
#tool nuget:?package=FriendlyEnvars&version=1.1.0
FriendlyEnvars
Simple, type-safe environment variable configuration for .NET
👀 Overview
Do you need to configure your .NET app purely via environment variables?
FriendlyEnvars lets you bind them directly to strongly typed configuration classes.
- Clean, explicit configuration mapping using the
[Envar]attribute. - Automatic type conversion, validation, and integration with the
IOptions<T>pattern. - Environment variables are bound once, at startup.
Ideal for: cloud-native apps, containerized deployments, microservices, or anywhere configuration comes from the environment.
📝 Why FriendlyEnvars?
- Type safety: Eliminates runtime configuration errors by mapping environment variables directly to typed properties.
- Built-in validation: Leverages data annotation attributes like
[Required],[Range], etc. automatically. - No boilerplate: No need to write manual parsing, error handling, or default value logic.
- Works with
IOptions: Smooth experience for modern .NET dependency injection patterns. - Explicit & Discoverable: Your configuration surface is crystal clear in the code.
🚀 Quick Start
1. Define Your Configuration Class
Annotate properties you want loaded from environment variables. Properties must have a setter (set or init):
public record DatabaseSettings
{
[Envar("DB_HOST")]
public string Host { get; init; } = string.Empty;
[Envar("DB_PORT")]
public int Port { get; init; }
[Envar("DB_SSL_ENABLED")]
public bool SslEnabled { get; init; } = true;
[Envar("DB_CONNECTION_TIMEOUT")]
public TimeSpan ConnectionTimeout { get; init; } = TimeSpan.FromSeconds(30);
}
2. Register in DI
Hook up configuration binding in your Startup.cs or DI setup:
services
.AddOptions<DatabaseSettings>()
.BindEnvars();
3. Add Validation (Optional)
Validate environment variables using standard data annotation attributes:
services
.AddOptions<DatabaseSettings>()
.BindEnvars()
.ValidateDataAnnotations()
.ValidateOnStart();
4. Inject and Use Your Config
public class MyService
{
public MyService(IOptions<DatabaseSettings> settings)
{
var dbSettings = settings.Value;
}
}
💡 Features
Supported Types:
string,char,bool- Numeric types:
byte,sbyte,short,ushort,int,uint,long,ulong,float,double,decimal Guid,Uri,TimeSpan,DateTime,DateTimeOffset,DateOnly,TimeOnlyEnum(case-insensitive, including[Flags]enums)- Nullable versions of all above types
- Any type with a
TypeConverter
Additional Features:
- Automatic conversion using invariant culture (by default) or custom culture.
- Custom parsing recipes via
IEnvarPropertyBinderinterface. - Validation using familiar
DataAnnotationsattributes.
⚙️ Advanced Usage
Parsing with a Specific Culture
By default, conversions use CultureInfo.InvariantCulture for predictable parsing. To handle locale-specific formats:
using System.Globalization;
services.AddOptions<DatabaseSettings>()
.BindEnvars(settings => {
settings.UseCulture(CultureInfo.GetCultureInfo("en-US"));
});
Custom Type Conversion
For complex types, implement IEnvarPropertyBinder to control parsing:
using System;
using System.Collections.Generic;
using System.Globalization;
public record ConnectionString
{
public string Host { get; init; } = string.Empty;
public int Port { get; init; }
public string User { get; init; } = string.Empty;
public string Password { get; init; } = string.Empty;
}
public class CustomEnvarPropertyBinder : IEnvarPropertyBinder
{
private readonly DefaultEnvarPropertyBinder _defaultBinder = new();
public object? Convert(string value, Type targetType, CultureInfo culture)
{
if (targetType == typeof(ConnectionString))
{
return ParseConnectionString(value);
}
return _defaultBinder.Convert(value, targetType, culture);
}
private static ConnectionString ParseConnectionString(string connectionString)
{
var pairs = connectionString.Split(';', StringSplitOptions.RemoveEmptyEntries);
var values = new Dictionary<string, string>();
foreach (var pair in pairs)
{
var parts = pair.Split('=', 2);
if (parts.Length == 2)
{
values[parts[0].Trim()] = parts[1].Trim();
}
}
return new ConnectionString
{
Host = values.GetValueOrDefault("Host", "localhost"),
Port = int.Parse(values.GetValueOrDefault("Port", "5432")),
User = values.GetValueOrDefault("User", ""),
Password = values.GetValueOrDefault("Password", "")
};
}
}
Usage with environment variable CONNECTION_STRING=Host=localhost;Port=5432;User=Joe;Password=Joe12:
public record DatabaseSettings
{
[Envar("CONNECTION_STRING")]
public ConnectionString Connection { get; init; } = new();
}
Then, configure the binder:
services.AddOptions<DatabaseSettings>()
.BindEnvars(settings =>
{
settings.UseCustomEnvarPropertyBinder(new CustomEnvarPropertyBinder());
});
Working with IOptionsSnapshot and IOptionsMonitor
By default, IOptionsSnapshot<T> and IOptionsMonitor<T> are enabled and will always reflect the values from app startup.
Environment variable configs do not refresh at runtime.
You can disable support for IOptionsSnapshot<T> and IOptionsMonitor<T> if you want to ensure only IOptions<T> is used:
services.AddOptions<DatabaseSettings>()
.BindEnvars(settings =>
{
settings
.BlockOptionsSnapshot()
.BlockOptionsMonitor();
});
⚠️ Breaking Changes
Empty Environment Variables (v2.x)
Previously, environment variables set to an empty string ("") were treated the same as unset variables — the property would retain its default value. Now, empty strings are passed to the binder. This means:
stringproperties will be set to""instead of keeping their default.- Non-string properties (e.g.,
int,bool) will throw aFormatExceptionwrapped inEnvarsExceptionif the environment variable is empty.
If you relied on the old behavior of ignoring empty values, either unset the variable entirely or use a custom IEnvarPropertyBinder to handle empty strings.
⚠️ Limitations
- No runtime refresh: environment variables are read once on application startup.
IOptionsSnapshotandIOptionsMonitorare enabled by default as read-only views, but can be disabled if needed.
With FriendlyEnvars, configuration is easy, explicit, and safe.
| 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
- Microsoft.Extensions.Options (>= 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.
## Breaking Changes
- Empty environment variables ("") are now passed to the binder instead of being treated as unset. String properties will be set to "" instead of keeping defaults; non-string properties will throw FormatException for empty values.
## New Features
- [Flags] enum support for combined values (e.g., "Read, Write")
## Bug Fixes
- Fixed enum values not being returned from the binder
- TypeConverter conversions now respect the configured culture setting
- Changed char parsing to use char.Parse() for clearer error messages
## Performance
- Added property metadata caching to avoid repeated reflection