Claude-skill-registry add-env-variable
Add a new environment variable to the application. Use when adding configuration for external services, feature flags, or application settings. Triggers on "add env", "environment variable", "config variable".
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/add-env-variable" ~/.claude/skills/majiayu000-claude-skill-registry-add-env-variable && rm -rf "$T"
manifest:
skills/data/add-env-variable/SKILL.mdsafety · automated scan (low risk)
This is a pattern-based risk scan, not a security review. Our crawler flagged:
- references .env files
- references API keys
Always read a skill's source content before installing. Patterns alone don't mean the skill is malicious — but they warrant attention.
source content
Add Environment Variable
Adds a new environment variable with Zod validation. All environment variables must be defined in
src/env.ts and documented in .env.example.
Quick Reference
Files to modify:
- Add to schema and mappingsrc/env.ts
- Document the variable.env.example
- Add validation teststests/env.test.ts
Instructions
Step 1: Add to Schema in src/env.ts
src/env.tsAdd the variable to the
envSchema object:
const envSchema = z.object({ // ... existing variables ... // Your new variable (with comment explaining purpose) NEW_VARIABLE: z.string(), // Required string // OR NEW_VARIABLE: z.string().optional(), // Optional string // OR NEW_VARIABLE: z.string().default("default-value"), // With default // OR NEW_VARIABLE: z.coerce.number().default(3000), // Number with coercion // OR NEW_VARIABLE: z.string().url(), // URL validation });
Step 2: Add to Mapping Object
Add the variable to
mappedEnv using the getEnv() helper (which reads prefixed variables):
const mappedEnv = { // ... existing mappings ... NEW_VARIABLE: getEnv("NEW_VARIABLE"), };
Step 3: Document in .env.example
.env.exampleAdd the variable with a descriptive comment, using the prefix (default:
BT_):
# Description of what this variable is for BT_NEW_VARIABLE=example-value
Note: The prefix is defined in
assrc/env.ts. Change this when creating a new service from the template.const PREFIX = "BT"
Step 4: Add Tests in tests/env.test.ts
tests/env.test.tsAdd test cases for the new variable:
it("accepts valid NEW_VARIABLE", () => { const parsed = envSchema.parse({ NEW_VARIABLE: "valid-value" }); expect(parsed.NEW_VARIABLE).toBe("valid-value"); }); it("defaults NEW_VARIABLE if missing", () => { const parsed = envSchema.parse({}); expect(parsed.NEW_VARIABLE).toBe("default-value"); }); // OR for optional it("accepts missing NEW_VARIABLE", () => { const parsed = envSchema.parse({}); expect(parsed.NEW_VARIABLE).toBeUndefined(); }); // OR for required it("rejects missing NEW_VARIABLE", () => { expect(() => envSchema.parse({})).toThrow(); });
Common Patterns
All examples use the
getEnv() helper and BT_ prefix:
Required String
// Schema MY_API_KEY: z.string(), // Mapping MY_API_KEY: getEnv("MY_API_KEY"), // .env.example BT_MY_API_KEY=your-api-key-here
Optional String
// Schema OPTIONAL_FEATURE: z.string().optional(), // Mapping OPTIONAL_FEATURE: getEnv("OPTIONAL_FEATURE"), // .env.example # Optional: Enable feature X # BT_OPTIONAL_FEATURE=enabled
String with Default
// Schema LOG_LEVEL: z.string().default("info"), // Mapping LOG_LEVEL: getEnv("LOG_LEVEL"), // .env.example BT_LOG_LEVEL=info
Number with Coercion
// Schema RATE_LIMIT: z.coerce.number().default(100), // Mapping RATE_LIMIT: getEnv("RATE_LIMIT"), // .env.example BT_RATE_LIMIT=100
URL Validation
// Schema WEBHOOK_URL: z.string().url().optional(), // Mapping WEBHOOK_URL: getEnv("WEBHOOK_URL"), // .env.example # Webhook endpoint for notifications BT_WEBHOOK_URL=https://example.com/webhook
Enum Values
// Schema NODE_ENV: z.enum(["development", "test", "production"]).default("development"), // Mapping NODE_ENV: getEnv("NODE_ENV"), // .env.example BT_NODE_ENV=development
Boolean (as string)
// Schema ENABLE_FEATURE: z.string().transform(v => v === "true").default("false"), // Mapping ENABLE_FEATURE: getEnv("ENABLE_FEATURE"), // .env.example BT_ENABLE_FEATURE=false
Usage in Code
Always import from
@/env, never use process.env directly:
import { env } from "@/env"; // Correct const apiKey = env.MY_API_KEY; // Wrong - bypasses validation const apiKey = process.env.MY_API_KEY;
Full Example: Adding Email Service Config
1. Update src/env.ts
src/env.tsconst envSchema = z.object({ // ... existing ... // Email service configuration EMAIL_API_KEY: z.string().optional(), EMAIL_FROM_ADDRESS: z.string().email().optional(), EMAIL_PROVIDER: z.enum(["sendgrid", "mailgun"]).default("sendgrid"), }); const mappedEnv = { // ... existing ... EMAIL_API_KEY: getEnv("EMAIL_API_KEY"), EMAIL_FROM_ADDRESS: getEnv("EMAIL_FROM_ADDRESS"), EMAIL_PROVIDER: getEnv("EMAIL_PROVIDER"), };
2. Update .env.example
.env.example# Email service configuration BT_EMAIL_API_KEY=your-email-api-key BT_EMAIL_FROM_ADDRESS=noreply@example.com BT_EMAIL_PROVIDER=sendgrid
3. Update tests/env.test.ts
tests/env.test.tsit("accepts valid email configuration", () => { const parsed = envSchema.parse({ EMAIL_API_KEY: "test-key", EMAIL_FROM_ADDRESS: "test@example.com", EMAIL_PROVIDER: "mailgun", }); expect(parsed.EMAIL_API_KEY).toBe("test-key"); expect(parsed.EMAIL_FROM_ADDRESS).toBe("test@example.com"); expect(parsed.EMAIL_PROVIDER).toBe("mailgun"); }); it("defaults EMAIL_PROVIDER to sendgrid", () => { const parsed = envSchema.parse({}); expect(parsed.EMAIL_PROVIDER).toBe("sendgrid"); }); it("rejects invalid EMAIL_FROM_ADDRESS", () => { expect(() => envSchema.parse({ EMAIL_FROM_ADDRESS: "not-an-email" }), ).toThrow(); }); it("rejects invalid EMAIL_PROVIDER", () => { expect(() => envSchema.parse({ EMAIL_PROVIDER: "invalid" })).toThrow(); });
What NOT to Do
- Do NOT use
directly in application codeprocess.env - Do NOT forget to add the mapping in
mappedEnv - Do NOT skip documenting in
.env.example - Do NOT skip adding tests for validation rules
- Do NOT store secrets in
(use placeholder values).env.example
See Also
- Services that use environment configcreate-utility-service
- Testing Zod schemas (similar patterns)test-schema