Przejdź do treści
Biblioteka skilli
DevOps i chmura · Planowanie

config-environments

/config-environments

Projektuje konfigurację wielu środowisk, izolację poświadczeń i dostarczanie sekretów, w tym schematy zmiennych środowiskowych i wybór poświadczeń zależny od środowiska.

Repozytorium
claude-config ↗
Licencja
MIT
Ostatnia zmiana repozytorium
27.10.2026

Ocena i bezpieczeństwo

100/ 100Klasa: dobry
Format25 / 25
Frontmatter z nazwą i opisem, poprawna nazwa, opis do 1024 znaków, nazwa zgodna z folderem.
Odkrywalność25 / 25
Opis mówi, kiedy użyć skilla, ma sensowną długość i jest w 3. osobie.
Treść35 / 35
Co najmniej 150 słów i do 500 linii, nagłówki, listy kroków, przykłady albo kod.
Higiena15 / 15
Bez zaślepek typu TODO, bez ścieżek Windows, z licencją.
Ryzykobrak sygnałów w skanie
Pliki w paczce
2
Skrypty
0
Komentarze HTML
0
Adresy URL w SKILL.md
0
Przestarzałość

Brak sygnałów. Repozytorium zmienione 27.10.2026, bez odwołań do wycofanych modeli i API.

Licencja

MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.

Co robi i kiedy

Projektuje konfigurację wielu środowisk, izolację poświadczeń i dostarczanie sekretów, w tym schematy zmiennych środowiskowych i wybór poświadczeń zależny od środowiska.

Oryginalny opis (EN)

Multi-environment config design, credential isolation, and secrets provisioning. TRIGGER when: designing or reviewing env-var schemes, branching-on-environment credential selection, or secret-isolation strategies. DO NOT TRIGGER when: a process legitimately holds both env values simultaneously (migrations, test harnesses) or single-environment apps.

Jak działa

  1. Core principle
  2. Runtime env-access APIs (quick reference)
  3. Why
  4. Anti-patterns to flag
  5. Environment-aware behavior vs environment-aware credentials
  6. When suffix patterns ARE legitimate
  7. Centralize config at startup (config.ts pattern)
  8. Isolation patterns that actually work
  9. CI/CD and build-time config
  10. Review checklist
Sekcje z nagłówków SKILL.md, w oryginale · 163 linii, 1 141 słów
Podgląd SKILL.md
---
name: config-environments
description: >
  Multi-environment config design, credential isolation, and secrets provisioning.
  TRIGGER when:
  designing or reviewing env-var schemes, branching-on-environment
  credential selection, or secret-isolation strategies.
  DO NOT TRIGGER when: a process legitimately holds both env values
  simultaneously (migrations, test harnesses) or single-environment apps.
user-invocable: false
---

# Config Across Environments

## Core principle

**Use the same variable name in every environment; different deployments populate it with different values.**

```
# Production (Vercel / Railway / Fly env store)
DATABASE_URL=postgres://prod-host/app

# Local (.env.local, not committed)
DATABASE_URL=postgres://localhost/app
```

Not:

```
# Anti-pattern — encoding environment in the variable name
DATABASE_URL_PROD=postgres://prod-host/app
DATABASE_URL_DEV=postgres://localhost/app
```

The environment is **implicit in which config source is loaded**, not explicit in the variable name.

## Runtime env-access APIs (quick reference)

| Runtime | Idiom |
|---|---|
| Node.js, Next.js server | `process.env.FOO` |
| Bun | `process.env.FOO` or `Bun.env.FOO` |
| Deno, Deno Deploy, Supabase Edge Functions | `Deno.env.get('FOO')` |
| Cloudflare Workers | `env.FOO` (typed via `Bindings`) |
| Browser bundles | Build-time only: Vite `import.meta.env.VITE_FOO`, Next.js `process.env.NEXT_PUBLIC_FOO` inlined at build |

Don't mix idioms across modules in the same runtime — it makes scattered reads harder to grep and breaks the "read once" pattern below.

## Why

- **12-Factor §III Config** explicitly rejects environment-named variables: *"env vars are granular controls, each fully orthogonal to other env vars. They are never grouped together as 'environments'."*
- **Suffix patterns duplicate logic** — the env-source selection is already made by which config file loads; `_DEV`/`_PROD` re-encodes that same decision in runtime `NODE_ENV` branches, forcing both values to exist for a variable only one of which is ever read.
- **Rotation is cheaper with canonical names** — one name to update in the prod store, versus remembering which suffix prod reads and risking an overlooked `_DEV` variant.
- **Mainstream frameworks resolve per-env config by file/store selection, not renaming:** Next.js lookup order, Rails per-env credentials, Kubernetes Kustomize overlays, Docker Compose `--env-file` — all load different sources for the same variable name.

## Anti-patterns to flag

### 1. Environment-suffixed variable names

```ts
// Bad
const clientId = process.env.NODE_ENV === 'production'
  ? process.env.OAUTH_CLIENT_ID_PROD
  : process.env.OAUTH_CLIENT_ID_DEV;

// Good
const clientId = process.env.OAUTH_CLIENT_ID;
```

### 2. Environment-branching for credential selection

```ts
// Bad
function getStripeKey() {
  return currentEnv() === 'production'
    ? Deno.env.get('STRIPE_SECRET_KEY_LIVE')
    : Deno.env.get('STRIPE_SECRET_KEY_TEST');
}
```

**Recommended:** each env's config source populates `STRIPE_SECRET_KEY` with its own key (`sk_live_…` prod, `sk_test_…` dev) — the value prefix encodes the mode, so no code branch is needed.

### 3. Sentinel-value defaults that silently leak production-shaped state

```ts
// Bad — silently falls back to a prod-ish default
const bucket = process.env.STORAGE_BUCKET ?? 'prod-uploads';

// Good — missing config fails boot, not first write
const bucket = process.env.STORAGE_BUCKET;
if (!bucket) throw new Error('STORAGE_BUCKET missing');
```

Non-sensitive defaults (`PORT`, `LOG_LEVEL`, `MAX_RETRIES`) are fine; fail fast instead when a default could point at live production state (`STORAGE_BUCKET`, `DATABASE_URL`, `STRIPE_SECRET_KEY`).

### 4. Assuming client-side frameworks "know" the environment

Client bundles (`VITE_*`/`NEXT_PUBLIC_*`) bake env vars in at build time only — building the prod bundle under staging's env ships the wrong values permanently.

## Environment-aware *behavior* vs environment-aware *credentials*

- **Credential selection branching is the anti-pattern.** Reading `X_DEV` vs `X_PROD` based on `NODE_ENV` is duplicated logic.
- **Behavior branching can be legitimate.** If the *same canonical variable* drives the decision, the env check lives in one place and only affects behavior.

```ts
// Legitimate: behavior differs, credentials are a single-name read
const origins = currentEnv() === 'production' ? PRODUCTION_ORIGINS : DEV_ORIGINS;
const clientId = process.env.OAUTH_CLIENT_ID; // same name in every env
```

## When suffix patterns ARE legitimate

- **Co-located simultaneous values** — a migration script reading `OLD_DATABASE_URL` and `NEW_DATABASE_URL` in one process.
- **Test harness stubs** — `TEST_STRIPE_KEY` next to `STRIPE_SECRET_KEY` so a test hits test mode deliberately.
- **Feature flags orthogonal to environment** — `ENABLE_NEW_BILLING` is a rollout control, not an environment name. Where the toggle should live, and whether it needs a flag platform, is the `feature-flags` skill's call, not this one's.

If a single invocation needs both suffixed values at the same time, the suffix is fine. If it's just "I'm in dev vs prod," it's the anti-pattern.

## Centralize config at startup (`config.ts` pattern)

Read every env var **once**, in a single module, validate at process boot, freeze, and export a typed object.

```ts
// config.ts — the one place env vars are read.
import { z } from 'zod';

const schema = z.object({
  DATABASE_URL: z.string().url(),
  STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
  OAUTH_CLIENT_ID: z.string().min(1),
  PORT: z.coerce.number().int().positive().default(3000),
  LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});

export const config = Object.freeze(schema.parse(process.env));
```

Benefits: fail-fast (missing config crashes at boot), type safety, central audit surface (one grep of `process.env.`), testability (`vi.mock('./config', () => ({ config: { ... } }))`).

| Language / stack | Config module | Common libraries |
|---|---|---|
| TypeScript / Node / Bun | `src/config.ts` or `src/env.ts` | Zod, valibot, envalid, `@t3-oss/env-core` |
| Python | `config.py` or `settings.py` | `pydantic-settings`, `dynaconf` |
| Go | `internal/config/config.go` | `caarlos0/env`, `spf13/viper`; validate with `go-playground/validator` |
| Ruby / Rails | `config/environments/*.rb` + credentials | Built-in `Rails.application.credentials` |
| Java / Kotlin / Spring Boot | `@ConfigurationProperties` class | Jakarta Bean Validation |
| Rust | `src/config.rs` | `config`/`figment` + `serde`; validate with `validator`; `.env` via `dotenvy` |

## Isolation patterns that actually work

Enforce **credential isolation** at provisioning time, not in code:

- Register separate upstream credentials per env (OAuth clients, API keys, service accounts).
- Each env's config source holds only its own credential — prod values live only in the prod secret store.
- Code reads a single canonical name and trusts the source to have populated the right value.

## CI/CD and build-time config

- **GitHub Actions `secrets.*` vs `vars.*`.** `secrets.*` is masked in logs; `vars.*` is plaintext-logged — never put a secret in `vars.*`.
- **Build-time vs runtime env.** A Docker image built with `ENV FOO=bar` bakes `FOO` into every container. For `NEXT_PUBLIC_*` / `VITE_*`, build-time is the *only* injection point — see anti-pattern #4.

## Review checklist

1. **Are there variables whose names contain `_DEV`, `_PROD`, `_STAGING`, `_TEST`?** Flag unless the "simultaneous values in one process" criterion applies.
2. **Does the code branch on `NODE_ENV` / `ENVIRONMENT` to pick a credential?** Collapse to a single env var read.
3. **Are missing stateful env vars handled with a production-shaped sentinel default?** Fail loudly for credentials, URLs, bucket names.
4. **Does the client bundle resolve env vars at build time?** Verify the prod bundle was built with prod env vars.
5. **Is "environment" conflated with "tenant" or "feature flag"?** Those are different axes. Toggle placement is the `feature-flags` skill's call.
6. **Are `process.env` / `Deno.env.get(...)` reads scattered across many files?** Consolidate into `config.ts`.
7. **Are env vars read inside functions/handlers instead of at module scope?** Request-path reads hide missing-config failures from boot-time validation.
8. **Is there boot-time validation of required env vars?** Schema parsed on startup, not on first use.
9. **Do tests stub `process.env` directly instead of mocking the config module?** `vi.mock('./config', () => …)` is cleaner.
10. **Are env var reads flowing into callers untyped (`string | undefined`)?** Narrow via validation or assert non-null at boot.
Pliki w paczce (2)
  • REFERENCES.md 3 KB
  • SKILL.md 9 KB

Wersje

W bazie nie ma innych skilli o nazwie config-environments.

Migawka bazy z 28.10.2026 · wersja paczki c75e41a163fa (skrót SHA-256 całej paczki)

Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.

Podobne skille

  • 100vercel-multi-env-setup
    Konfiguruje Vercel dla środowisk development, preview i production z sekretami przypisanymi do środowisk i izolacją konfiguracji.
  • 100env-vars
    Doradza w sprawie zmiennych środowiskowych Vercel: pliki .env, polecenia vercel env, typy Secret i Config, tokeny OIDC i konfiguracja zależna od środowiska.
  • 100arn-infra-env
    Konfiguruje środowiska dev, staging i produkcja, ich izolację, konfigurację na środowisko (na przykład tfvars) i promocję między nimi.
  • 100env-manager
    Zarządza zmiennymi środowiskowymi i sekretami w środowiskach development, staging i produkcji: audyt, synchronizacja, wykrywanie braków i rotacja poświadczeń.
  • 100mistral-multi-env-setup
    Izoluje środowiska Mistral: deweloperskie, stagingowe i produkcyjne według workspace'u, poświadczeń, danych, budżetu i polityki routingu.
  • 100environment-setup
    Konfiguruje środowiska development, staging i produkcyjne: zmienne środowiskowe, pliki .env, zarządzanie konfiguracją i ustawienia zależne od środowiska.

Uwagi i zgłoszenia

Wiadomość trafi do Bartosza Sokolińskiego. Adres e-mail jest potrzebny tylko do odpowiedzi. Szczegóły w polityce prywatności.