xiaohongshu
xiaohongshu
environment-config
Centralized environment variable management with validation. Fail fast at startup if config is invalid. Supports multi-environment setups (dev/staging/prod) with type-safe access.
Full skill instructions
Centralized, validated environment variables that fail fast at startup.
project/
├── .env # Local development (gitignored)
├── .env.example # Template (committed)
├── .env.production # Production overrides (gitignored or in CI)
├── .env.local # Local overrides (gitignored)
└── src/
└── lib/
└── env.ts # Validation and exports
// lib/env.ts
import { z } from 'zod';
/**
* Server-side environment variables.
* These are NOT exposed to the browser.
*/
const serverSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
// Database
DATABASE_URL: z.string().url(),
// External services
API_URL: z.string().url().default('http://localhost:8787'),
REDIS_URL: z.string().url().optional(),
// Feature flags
ENABLE_ANALYTICS: z.coerce.boolean().default(false),
ENABLE_RATE_LIMITING: z.coerce.boolean().default(true),
// Secrets
JWT_SECRET: z.string().min(32),
// Logging
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});
/**
* Client-side environment variables.
* MUST be prefixed with NEXT_PUBLIC_ (Next.js) or VITE_ (Vite)
*/
const clientSchema = z.object({
NEXT_PUBLIC_API_URL: z.string().url(),
NEXT_PUBLIC_APP_URL: z.string().url().optional(),
});
// Validate at module load time
const serverEnv = serverSchema.safeParse(process.env);
const clientEnv = clientSchema.safeParse(process.env);
if (!serverEnv.success) {
console.error('❌ Invalid server environment variables:');
console.error(JSON.stringify(serverEnv.error.flatten().fieldErrors, null, 2));
throw new Error('Invalid server environment configuration');
}
if (!clientEnv.success) {
console.error('❌ Invalid client environment variables:');
console.error(JSON.stringify(clientEnv.error.flatten().fieldErrors, null, 2));
throw new Error('Invalid client environment configuration');
}
/**
* Type-safe server environment.
* Use this in API routes and server components.
*/
export const env = serverEnv.data;
/**
* Type-safe client environment.
* Use this in client components.
*/
export const publicEnv = clientEnv.data;
// Type exports
export type Env = z.infer<typeof serverSchema>;
export type PublicEnv = z.infer<typeof clientSchema>;
// lib/env.ts - No external dependencies
function requireEnv(key: string): string {
const value = process.env[key];
if (!value) {
throw new Error(`Missing required environment variable: ${key}`);
}
return value;
}
function optionalEnv(key: string, defaultValue: string): string {
return process.env[key] || defaultValue;
}
function boolEnv(key: string, defaultValue: boolean): boolean {
const value = process.env[key];
if (value === undefined) return defaultValue;
return value === 'true' || value === '1';
}
function intEnv(key: string, defaultValue: number): number {
const value = process.env[key];
if (value === undefined) return defaultValue;
const parsed = parseInt(value, 10);
if (isNaN(parsed)) {
throw new Error(`Environment variable ${key} must be a number`);
}
return parsed;
}
export const env = {
// Required
DATABASE_URL: requireEnv('DATABASE_URL'),
JWT_SECRET: requireEnv('JWT_SECRET'),
// Optional with defaults
API_URL: optionalEnv('API_URL', 'http://localhost:8787'),
LOG_LEVEL: optionalEnv('LOG_LEVEL', 'info'),
PORT: intEnv('PORT', 3000),
// Booleans
ENABLE_ANALYTICS: boolEnv('ENABLE_ANALYTICS', false),
ENABLE_RATE_LIMITING: boolEnv('ENABLE_RATE_LIMITING', true),
// Computed
isDev: process.env.NODE_ENV === 'development',
isProd: process.env.NODE_ENV === 'production',
isTest: process.env.NODE_ENV === 'test',
} as const;
// Validate on import
Object.keys(env); // Triggers all getters
# config/settings.py
from pydantic_settings import BaseSettings
from pydantic import Field, field_validator
from typing import Literal
from functools import lru_cache
class Settings(BaseSettings):
"""Application settings with validation."""
# Environment
environment: Literal["development", "production", "test"] = "development"
debug: bool = False
# Database
database_url: str = Field(..., description="PostgreSQL connection string")
# External services
api_url: str = "http://localhost:8787"
redis_url: str | None = None
# Feature flags
enable_analytics: bool = False
enable_rate_limiting: bool = True
# Secrets
jwt_secret: str = Field(..., min_length=32)
# Logging
log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "INFO"
@field_validator("database_url")
@classmethod
def validate_database_url(cls, v: str) -> str:
if not v.startswith(("postgresql://", "postgres://")):
raise ValueError("database_url must be a PostgreSQL connection string")
return v
@property
def is_dev(self) -> bool:
return self.environment == "development"
@property
def is_prod(self) -> bool:
return self.environment == "production"
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
case_sensitive = False
@lru_cache
def get_settings() -> Settings:
"""Cached settings instance. Call once at startup."""
return Settings()
# Validate on import
settings = get_settings()
# config/settings.py
import os
from dataclasses import dataclass
from typing import Optional
class ConfigError(Exception):
"""Raised when configuration is invalid."""
pass
def require_env(key: str) -> str:
"""Get required environment variable or raise."""
value = os.getenv(key)
if not value:
raise ConfigError(f"Missing required environment variable: {key}")
return value
def optional_env(key: str, default: str) -> str:
"""Get optional environment variable with default."""
return os.getenv(key, default)
def bool_env(key: str, default: bool) -> bool:
"""Get boolean environment variable."""
value = os.getenv(key)
if value is None:
return default
return value.lower() in ("true", "1", "yes")
def int_env(key: str, default: int) -> int:
"""Get integer environment variable."""
value = os.getenv(key)
if value is None:
return default
try:
return int(value)
except ValueError:
raise ConfigError(f"Environment variable {key} must be an integer")
@dataclass(frozen=True)
class Settings:
"""Immutable application settings."""
# Required
database_url: str
jwt_secret: str
# Optional
api_url: str
log_level: str
port: int
# Feature flags
enable_analytics: bool
enable_rate_limiting: bool
# Computed
is_dev: bool
is_prod: bool
is_test: bool
def load_settings() -> Settings:
"""Load and validate settings from environment."""
return Settings(
database_url=require_env("DATABASE_URL"),
jwt_secret=require_env("JWT_SECRET"),
api_url=optional_env("API_URL", "http://localhost:8787"),
log_level=optional_env("LOG_LEVEL", "INFO"),
port=int_env("PORT", 8000),
enable_analytics=bool_env("ENABLE_ANALYTICS", False),
enable_rate_limiting=bool_env("ENABLE_RATE_LIMITING", True),
is_dev=os.getenv("ENVIRONMENT", "development") == "development",
is_prod=os.getenv("ENVIRONMENT") == "production",
is_test=os.getenv("ENVIRONMENT") == "test",
)
# Validate on import
settings = load_settings()
// In API routes
import { env } from '@/lib/env';
export async function GET() {
if (env.ENABLE_ANALYTICS) {
await trackEvent('api_call');
}
const response = await fetch(`${env.API_URL}/data`);
return Response.json(await response.json());
}
// In client components
import { publicEnv } from '@/lib/env';
const apiClient = createClient(publicEnv.NEXT_PUBLIC_API_URL);
# In FastAPI
from config.settings import settings
@app.get("/health")
async def health():
return {
"status": "healthy",
"environment": settings.environment,
"debug": settings.debug,
}
# In services
from config.settings import settings
async def process_data():
if settings.enable_analytics:
await track_event("data_processed")
# =============================================================================
# Required - App will not start without these
# =============================================================================
DATABASE_URL=postgresql://user:pass@localhost:5432/myapp
JWT_SECRET=your-secret-key-at-least-32-characters-long
# =============================================================================
# External Services
# =============================================================================
API_URL=http://localhost:8787
REDIS_URL=redis://localhost:6379
# =============================================================================
# Feature Flags
# =============================================================================
ENABLE_ANALYTICS=false
ENABLE_RATE_LIMITING=true
# =============================================================================
# App Config
# =============================================================================
NODE_ENV=development
LOG_LEVEL=debug
PORT=3000
# Environment files
.env
.env.local
.env.*.local
.env.production
.env.staging
# Keep the example
!.env.example
# Build args for client-side vars (baked into bundle)
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
# Runtime vars set via docker-compose or k8s
# docker-compose.yml
services:
app:
build: .
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
- JWT_SECRET=${JWT_SECRET}
env_file:
- .env.production
process.env calls in business logic.env.example is your config documentation.env files with secretsprocess.env directly throughout codebase.env.example (new devs can't onboard)xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience