Skip to main content
skill CX Codex

configuration — Claude Code skill: what it does, how to install

Guides .NET 10 configuration with typed options, validation, and secret handling. Use it when working with appsettings files or environment variables.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a claude-code
Open on GitHub

What configuration does

This skill sets configuration patterns for .NET 10 applications. It binds settings sections to typed classes with BindConfiguration, uses attribute validation, and applies ValidateOnStart() so invalid values fail during startup.

It maps immutable settings to IOptions<T>, request-scoped reloadable settings to IOptionsSnapshot<T>, and watched background-service settings to IOptionsMonitor<T>. Named options cover separate configurations of the same type.

For development secrets, it points to dotnet user-secrets; production secrets use environment variables or Azure Key Vault. Reading IConfiguration directly inside services is treated as an anti-pattern, so existing service code deserves a check.

What it helps with

  • bind an appsettings.json section to a typed class
  • validate required settings at startup
  • choose between IOptions<T> and IOptionsSnapshot<T>
  • move secrets out of appsettings.json
  • configure named SMTP option instances

Example prompts for the agent

  • Set up database configuration with DatabaseOptions and BindConfiguration.
  • Add JwtOptions validation with ValidateDataAnnotations() and ValidateOnStart().
  • Configure SMTP settings for internal and customer with named options.

How to install configuration

1Skills CLI (Vercel)

npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a claude-code

2Manually: put the files in place

~/.claude/skills/configuration/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/configuration/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

From the same set46

api-versioning Guides your agent through ASP.NET Core API versioning using the Asp.Versioning library. Useful when adding URL segment versions or deprecating legacy contracts. CX Codex +1 2,800installs caching Guides caching work in .NET 10 applications with HybridCache, response caching, and distributed cache patterns. Use it when reducing database reads or planning cache invalidation. CX Codex +1 2,800installs health-check Grades a .NET project across eight dimensions with letter marks A–F and a rolled-up GPA. Useful at onboarding, before a release, and after a cleanup sprint. CX Codex +1 2,800installs openapi Configures native OpenAPI generation in .NET 10 without Swashbuckle. Helps the agent handle transformers, TypedResults metadata, and security schemes. CX Codex +1 2,800installs scalar A skill that walks the agent through wiring Scalar into a .NET 10 app as a Swagger UI replacement, with themes, auth prefill and multiple documents. CX Codex +1 2,800installs opentelemetry Configures OpenTelemetry traces, metrics, and logs in .NET 10 applications using OTLP export and IMeterFactory. CX Codex +1 2,800installs messaging A .NET skill that walks your agent through Wolverine or MassTransit setup, the outbox pattern, sagas, and RabbitMQ or Azure Service Bus brokers. CX Codex +1 2,800installs project-structure A skill that tells your agent how to lay out a .NET solution: central package versions, shared build properties, .slnx format and naming rules. CX Codex +1 2,800installs

Similar

Questions about configuration

How do I install configuration in Claude Code?

Run npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a claude-code, then run npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a claude-code again. The skill file is placed at ~/.claude/skills/configuration/SKILL.md.

What does configuration do?

It provides .NET 10 patterns for the Options pattern, startup validation, configuration layers, and secret handling. It also guides the choice of an options interface for each scenario.

What is the difference between IOptions<T>, IOptionsSnapshot<T>, and IOptionsMonitor<T>?

IOptions<T> reads values at startup for immutable configuration. IOptionsSnapshot<T> reloads settings per request, while IOptionsMonitor<T> watches changes and exposes current values to a background service.

Source text

SKILL.md · MIT
---
name: configuration
description: >
  Configuration patterns for .NET 10 applications. Covers the Options pattern,
  IOptionsSnapshot vs IOptions, secrets management, and environment-based
  configuration.
  Load this skill when setting up application configuration, managing secrets,
  binding configuration sections, or when the user mentions "configuration",
  "appsettings", "Options pattern", "IOptions", "IOptionsSnapshot", "secrets",
  "user secrets", "environment variables", "connection string", or "config binding".
---

# Configuration

## Core Principles

1. **Options pattern always** — Never read `IConfiguration` directly in services. Bind configuration sections to strongly-typed classes with validation.
2. **Validate on startup** — Use `ValidateDataAnnotations()` and `ValidateOnStart()` to catch misconfiguration before the first request.
3. **Secrets never in source** — Use user secrets in development, Azure Key Vault or environment variables in production. Never commit secrets to git.
4. **Configuration layering** — `appsettings.json` → `appsettings.{Environment}.json` → environment variables → user secrets. Later sources override earlier ones.

## Patterns

### Options Pattern

```csharp
// Options class with validation attributes
public class DatabaseOptions
{
    public const string SectionName = "Database";

    [Required]
    public required string ConnectionString { get; init; }

    [Range(1, 100)]
    public int MaxRetryCount { get; init; } = 3;

    [Range(1, 60)]
    public int CommandTimeoutSeconds { get; init; } = 30;
}

// Registration with validation
builder.Services.AddOptions<DatabaseOptions>()
    .BindConfiguration(DatabaseOptions.SectionName)
    .ValidateDataAnnotations()
    .ValidateOnStart(); // Fails at startup if configuration is invalid
```

```json
// appsettings.json
{
  "Database": {
    "ConnectionString": "",
    "MaxRetryCount": 3,
    "CommandTimeoutSeconds": 30
  }
}
```

### Injecting Options

```csharp
// IOptions<T> — singleton, read once at startup, doesn't change
public class OrderService(IOptions<DatabaseOptions> options)
{
    private readonly DatabaseOptions _db = options.Value;
}

// IOptionsSnapshot<T> — scoped, re-reads per request (for reloadable config)
public class OrderService(IOptionsSnapshot<DatabaseOptions> options)
{
    private readonly DatabaseOptions _db = options.Value;
}

// IOptionsMonitor<T> — singleton, actively watches for changes
public class BackgroundWorker(IOptionsMonitor<WorkerOptions> options)
{
    public void DoWork()
    {
        var current = options.CurrentValue; // Always latest
    }
}
```

### Custom Validation (Complex Rules)

```csharp
builder.Services.AddOptions<JwtOptions>()
    .BindConfiguration("Jwt")
    .Validate(options =>
    {
        if (string.IsNullOrEmpty(options.Key) || options.Key.Length < 32)
            return false;
        if (options.ExpirationMinutes <= 0)
            return false;
        return true;
    }, "JWT key must be at least 32 characters and expiration must be positive")
    .ValidateOnStart();
```

### Azure Key Vault (Production)

```csharp
// Program.cs — add Key Vault as a configuration source
if (builder.Environment.IsProduction())
{
    var keyVaultUri = new Uri(builder.Configuration["KeyVault:Uri"]!);
    builder.Configuration.AddAzureKeyVault(keyVaultUri, new DefaultAzureCredential());
}
```

### Configuration for Multiple Environments

```csharp
// Named options — different config per named instance
builder.Services.AddOptions<SmtpOptions>("internal")
    .BindConfiguration("Smtp:Internal");
builder.Services.AddOptions<SmtpOptions>("customer")
    .BindConfiguration("Smtp:Customer");

// Usage
public class EmailService(IOptionsSnapshot<SmtpOptions> options)
{
    public async Task SendInternalEmail(string to, string body)
    {
        var smtp = options.Get("internal");
        // ...
    }
}
```

## Anti-patterns

### Don't Read IConfiguration Directly

```csharp
// BAD — stringly-typed, no validation, hard to test
public class OrderService(IConfiguration config)
{
    public void Process()
    {
        var timeout = int.Parse(config["Database:CommandTimeout"]!);
    }
}

// GOOD — strongly-typed options
public class OrderService(IOptions<DatabaseOptions> options)
{
    public void Process()
    {
        var timeout = options.Value.CommandTimeoutSeconds;
    }
}
```

### Don't Put Secrets in appsettings.json

```json
// BAD — committed to source control
{
  "Jwt": { "Key": "super-secret-key" },
  "Database": { "ConnectionString": "Server=prod;Password=secret" }
}

// GOOD — appsettings.json has defaults/structure only
{
  "Jwt": { "Key": "", "Issuer": "myapp", "Audience": "myapp" },
  "Database": { "ConnectionString": "" }
}
// Secrets provided via user-secrets (dev) or env vars / Key Vault (prod)
```

### Don't Skip Startup Validation

```csharp
// BAD — misconfiguration discovered at runtime
builder.Services.Configure<JwtOptions>(builder.Configuration.GetSection("Jwt"));

// GOOD — fail fast at startup
builder.Services.AddOptions<JwtOptions>()
    .BindConfiguration("Jwt")
    .ValidateDataAnnotations()
    .ValidateOnStart();
```

## Decision Guide

| Scenario | Recommendation |
|----------|---------------|
| Binding config to class | Options pattern with `BindConfiguration` |
| Simple, immutable config | `IOptions<T>` |
| Config that changes per request | `IOptionsSnapshot<T>` |
| Background service watching config | `IOptionsMonitor<T>` |
| Development secrets | `dotnet user-secrets` |
| Production secrets | Azure Key Vault or environment variables |
| Validating config | `ValidateDataAnnotations()` + `ValidateOnStart()` |
| Multiple configs of same type | Named options with `IOptionsSnapshot<T>.Get(name)` |

© codewithmukesh · MIT · codewithmukesh/dotnet-claude-kit

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor