home / skills / sickn33 / antigravity-awesome-skills / azure-appconfiguration-ts
This skill helps you manage centralized configuration with Azure App Configuration, including feature flags, dynamic refresh, and Key Vault integration.
npx playbooks add skill sickn33/antigravity-awesome-skills --skill azure-appconfiguration-tsReview the files below or copy the command above to add this skill to your agents.
---
name: azure-appconfiguration-ts
description: Build applications using Azure App Configuration SDK for JavaScript (@azure/app-configuration). Use when working with configuration settings, feature flags, Key Vault references, dynamic refresh, or centralized configuration management.
package: "@azure/app-configuration"
---
# Azure App Configuration SDK for TypeScript
Centralized configuration management with feature flags and dynamic refresh.
## Installation
```bash
# Low-level CRUD SDK
npm install @azure/app-configuration @azure/identity
# High-level provider (recommended for apps)
npm install @azure/app-configuration-provider @azure/identity
# Feature flag management
npm install @microsoft/feature-management
```
## Environment Variables
```bash
AZURE_APPCONFIG_ENDPOINT=https://<your-resource>.azconfig.io
# OR
AZURE_APPCONFIG_CONNECTION_STRING=Endpoint=https://...;Id=...;Secret=...
```
## Authentication
```typescript
import { AppConfigurationClient } from "@azure/app-configuration";
import { DefaultAzureCredential } from "@azure/identity";
// DefaultAzureCredential (recommended)
const client = new AppConfigurationClient(
process.env.AZURE_APPCONFIG_ENDPOINT!,
new DefaultAzureCredential()
);
// Connection string
const client2 = new AppConfigurationClient(
process.env.AZURE_APPCONFIG_CONNECTION_STRING!
);
```
## CRUD Operations
### Create/Update Settings
```typescript
// Add new (fails if exists)
await client.addConfigurationSetting({
key: "app:settings:message",
value: "Hello World",
label: "production",
contentType: "text/plain",
tags: { environment: "prod" },
});
// Set (create or update)
await client.setConfigurationSetting({
key: "app:settings:message",
value: "Updated value",
label: "production",
});
// Update with optimistic concurrency
const existing = await client.getConfigurationSetting({ key: "myKey" });
existing.value = "new value";
await client.setConfigurationSetting(existing, { onlyIfUnchanged: true });
```
### Read Settings
```typescript
// Get single setting
const setting = await client.getConfigurationSetting({
key: "app:settings:message",
label: "production", // optional
});
console.log(setting.value);
// List with filters
const settings = client.listConfigurationSettings({
keyFilter: "app:*",
labelFilter: "production",
});
for await (const setting of settings) {
console.log(`${setting.key}: ${setting.value}`);
}
```
### Delete Settings
```typescript
await client.deleteConfigurationSetting({
key: "app:settings:message",
label: "production",
});
```
### Lock/Unlock (Read-Only)
```typescript
// Lock
await client.setReadOnly({ key: "myKey", label: "prod" }, true);
// Unlock
await client.setReadOnly({ key: "myKey", label: "prod" }, false);
```
## App Configuration Provider
### Load Configuration
```typescript
import { load } from "@azure/app-configuration-provider";
import { DefaultAzureCredential } from "@azure/identity";
const appConfig = await load(
process.env.AZURE_APPCONFIG_ENDPOINT!,
new DefaultAzureCredential(),
{
selectors: [
{ keyFilter: "app:*", labelFilter: "production" },
],
trimKeyPrefixes: ["app:"],
}
);
// Map-style access
const value = appConfig.get("settings:message");
// Object-style access
const config = appConfig.constructConfigurationObject({ separator: ":" });
console.log(config.settings.message);
```
### Dynamic Refresh
```typescript
const appConfig = await load(endpoint, credential, {
selectors: [{ keyFilter: "app:*" }],
refreshOptions: {
enabled: true,
refreshIntervalInMs: 30_000, // 30 seconds
},
});
// Trigger refresh (non-blocking)
appConfig.refresh();
// Listen for refresh events
const disposer = appConfig.onRefresh(() => {
console.log("Configuration refreshed!");
});
// Express middleware pattern
app.use((req, res, next) => {
appConfig.refresh();
next();
});
```
### Key Vault References
```typescript
const appConfig = await load(endpoint, credential, {
selectors: [{ keyFilter: "app:*" }],
keyVaultOptions: {
credential: new DefaultAzureCredential(),
secretRefreshIntervalInMs: 7200_000, // 2 hours
},
});
// Secrets are automatically resolved
const dbPassword = appConfig.get("database:password");
```
## Feature Flags
### Create Feature Flag (Low-Level)
```typescript
import {
featureFlagPrefix,
featureFlagContentType,
FeatureFlagValue,
ConfigurationSetting,
} from "@azure/app-configuration";
const flag: ConfigurationSetting<FeatureFlagValue> = {
key: `${featureFlagPrefix}Beta`,
contentType: featureFlagContentType,
value: {
id: "Beta",
enabled: true,
description: "Beta feature",
conditions: {
clientFilters: [
{
name: "Microsoft.Targeting",
parameters: {
Audience: {
Users: ["[email protected]"],
Groups: [{ Name: "beta-testers", RolloutPercentage: 50 }],
DefaultRolloutPercentage: 0,
},
},
},
],
},
},
};
await client.addConfigurationSetting(flag);
```
### Load and Evaluate Feature Flags
```typescript
import { load } from "@azure/app-configuration-provider";
import {
ConfigurationMapFeatureFlagProvider,
FeatureManager,
} from "@microsoft/feature-management";
const appConfig = await load(endpoint, credential, {
featureFlagOptions: {
enabled: true,
selectors: [{ keyFilter: "*" }],
refresh: {
enabled: true,
refreshIntervalInMs: 30_000,
},
},
});
const featureProvider = new ConfigurationMapFeatureFlagProvider(appConfig);
const featureManager = new FeatureManager(featureProvider);
// Simple check
const isEnabled = await featureManager.isEnabled("Beta");
// With targeting context
const isEnabledForUser = await featureManager.isEnabled("Beta", {
userId: "[email protected]",
groups: ["beta-testers"],
});
```
## Snapshots
```typescript
// Create snapshot
const snapshot = await client.beginCreateSnapshotAndWait({
name: "release-v1.0",
retentionPeriod: 2592000, // 30 days
filters: [{ keyFilter: "app:*", labelFilter: "production" }],
});
// Get snapshot
const snap = await client.getSnapshot("release-v1.0");
// List settings in snapshot
const settings = client.listConfigurationSettingsForSnapshot("release-v1.0");
for await (const setting of settings) {
console.log(`${setting.key}: ${setting.value}`);
}
// Archive/recover
await client.archiveSnapshot("release-v1.0");
await client.recoverSnapshot("release-v1.0");
// Load from snapshot (provider)
const config = await load(endpoint, credential, {
selectors: [{ snapshotName: "release-v1.0" }],
});
```
## Labels
```typescript
// Create settings with labels
await client.setConfigurationSetting({
key: "database:host",
value: "dev-db.example.com",
label: "development",
});
await client.setConfigurationSetting({
key: "database:host",
value: "prod-db.example.com",
label: "production",
});
// Filter by label
const prodSettings = client.listConfigurationSettings({
keyFilter: "*",
labelFilter: "production",
});
// No label (null label)
const noLabelSettings = client.listConfigurationSettings({
labelFilter: "\0",
});
// List available labels
for await (const label of client.listLabels()) {
console.log(label.name);
}
```
## Key Types
```typescript
import {
AppConfigurationClient,
ConfigurationSetting,
FeatureFlagValue,
SecretReferenceValue,
featureFlagPrefix,
featureFlagContentType,
secretReferenceContentType,
ListConfigurationSettingsOptions,
} from "@azure/app-configuration";
import { load } from "@azure/app-configuration-provider";
import {
FeatureManager,
ConfigurationMapFeatureFlagProvider,
} from "@microsoft/feature-management";
```
## Best Practices
1. **Use provider for apps** - `@azure/app-configuration-provider` for runtime config
2. **Use low-level for management** - `@azure/app-configuration` for CRUD operations
3. **Enable refresh** - For dynamic configuration updates
4. **Use labels** - Separate configurations by environment
5. **Use snapshots** - For immutable release configurations
6. **Sentinel pattern** - Use a sentinel key to trigger full refresh
7. **RBAC roles** - `App Configuration Data Reader` for read-only access
This skill shows how to build TypeScript/JavaScript apps with the Azure App Configuration SDK (@azure/app-configuration and @azure/app-configuration-provider). It covers authentication, CRUD for configuration settings, feature flags, dynamic refresh, Key Vault references, snapshots, and labels to centralize and manage runtime configuration. Use it to implement centralized config, runtime refresh, and feature gating across environments.
The skill demonstrates both the low-level AppConfigurationClient for management (create, read, update, delete, snapshots, labels) and the high-level provider for application runtime consumption with convenient access patterns and automatic refresh. It shows authentication via DefaultAzureCredential or connection string, resolving Key Vault references, configuring refresh intervals, and integrating feature flags with @microsoft/feature-management.
Which package should I use in my app vs CI/management scripts?
Use @azure/app-configuration-provider in apps for runtime access and automatic refresh; use @azure/app-configuration for management scripts that perform explicit CRUD, snapshots, or label operations.
How do I securely access secrets referenced from App Configuration?
Configure Key Vault references and supply a credential (DefaultAzureCredential recommended); the provider can automatically resolve and refresh secrets at configured intervals.