Environment Configuration
Environment Configuration provides type-safe configuration management with Zod validation. Prevent runtime errors from misconfiguration.
Overview
Flowfull uses environment variables for configuration with:
- ✅ Zod validation
- ✅ Fail-fast on startup
- ✅ Type-safe access
- ✅ Clear error messages
- ✅ Auto-detection
Basic Configuration
.env File
env
# Server
PORT=3000
NODE_ENV=development
# Database
DATABASE_TYPE=postgresql
DATABASE_URL=postgresql://localhost:5432/mydb
# Flowless Integration
FLOWLESS_URL=https://your-instance.pubflow.com
BRIDGE_SECRET=your-bridge-secret-here
# Security
VALIDATION_MODE=STANDARD
# Cache (Optional)
CACHE_ENABLED=true
REDIS_URL=redis://localhost:6379
# PASETO (Optional)
PASETO_SECRET_KEY=your-paseto-secret-keyValidation Schema
typescript
import { z } from 'zod';
const envSchema = z.object({
// Server
PORT: z.string().default('3000'),
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
// Database
DATABASE_TYPE: z.enum(['postgresql', 'mysql', 'libsql']),
DATABASE_URL: z.string().url(),
DATABASE_AUTH_TOKEN: z.string().optional(),
// Flowless
FLOWLESS_URL: z.string().url(),
BRIDGE_SECRET: z.string().min(32),
// Security
VALIDATION_MODE: z.enum(['DISABLED', 'STANDARD', 'ADVANCED', 'STRICT']).default('STANDARD'),
// Cache
CACHE_ENABLED: z.string().transform(val => val === 'true').default('true'),
REDIS_URL: z.string().url().optional(),
// PASETO
PASETO_SECRET_KEY: z.string().optional(),
});
export type Env = z.infer<typeof envSchema>;
// Validate on startup
export const env = envSchema.parse(process.env);Usage
typescript
import { env } from './config/environment';
// Type-safe access
console.log(env.PORT); // string
console.log(env.CACHE_ENABLED); // boolean
console.log(env.VALIDATION_MODE); // 'DISABLED' | 'STANDARD' | 'ADVANCED' | 'STRICT'
// TypeScript knows the types!
const port = parseInt(env.PORT); // ✅ Type-safe
const cacheEnabled = env.CACHE_ENABLED; // ✅ booleanFail-Fast Validation
If configuration is invalid, the app fails on startup:
bash
$ bun run dev
❌ Environment validation failed:
- FLOWLESS_URL: Invalid URL
- BRIDGE_SECRET: String must contain at least 32 character(s)
- DATABASE_TYPE: Invalid enum value. Expected 'postgresql' | 'mysql' | 'libsql'
Fix your .env file and try again.Required vs Optional
typescript
const envSchema = z.object({
// Required
DATABASE_URL: z.string().url(),
// Optional with default
PORT: z.string().default('3000'),
// Optional without default
REDIS_URL: z.string().url().optional(),
});
// Usage
const port = env.PORT; // Always defined (has default)
const redisUrl = env.REDIS_URL; // May be undefinedTransformations
typescript
const envSchema = z.object({
// String to boolean
CACHE_ENABLED: z.string()
.transform(val => val === 'true')
.default('true'),
// String to number
PORT: z.string()
.transform(val => parseInt(val))
.default('3000'),
// String to array
ALLOWED_ORIGINS: z.string()
.transform(val => val.split(','))
.default('http://localhost:3000'),
});
// Usage
const cacheEnabled: boolean = env.CACHE_ENABLED;
const port: number = env.PORT;
const origins: string[] = env.ALLOWED_ORIGINS;Environment-Specific Config
typescript
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']),
// Development only
DEBUG: z.string().optional(),
// Production only
SENTRY_DSN: z.string().url().optional(),
});
// Conditional validation
if (env.NODE_ENV === 'production') {
if (!env.SENTRY_DSN) {
throw new Error('SENTRY_DSN required in production');
}
}Best Practices
✅ Do
- Validate all environment variables
- Use Zod for type safety
- Fail fast on invalid config
- Provide clear error messages
- Use .env.example for documentation
❌ Don't
- Skip validation
- Use process.env directly
- Hardcode secrets
- Commit .env to git
- Use default values for secrets
.env.example
Create a .env.example file for documentation:
env
# Server Configuration
PORT=3000
NODE_ENV=development
# Database Configuration
DATABASE_TYPE=postgresql
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
# Flowless Integration
FLOWLESS_URL=https://your-instance.pubflow.com
BRIDGE_SECRET=your-bridge-secret-here
# Security Configuration
VALIDATION_MODE=STANDARD
# Cache Configuration (Optional)
CACHE_ENABLED=true
REDIS_URL=redis://localhost:6379
# PASETO Configuration (Optional)
PASETO_SECRET_KEY=your-paseto-secret-keyLoading Environment
typescript
// Load .env file
import 'dotenv/config';
// Or with custom path
import { config } from 'dotenv';
config({ path: '.env.local' });
// Validate
import { env } from './config/environment';Multiple Environments
bash
# Development
.env.development
# Production
.env.production
# Test
.env.testLoad based on NODE_ENV:
typescript
import { config } from 'dotenv';
const envFile = `.env.${process.env.NODE_ENV || 'development'}`;
config({ path: envFile });Secrets Management
Development
env
# .env (not committed)
BRIDGE_SECRET=dev-secret-keyProduction
Use environment variables from your hosting provider:
- Vercel: Environment Variables
- Railway: Environment Variables
- Fly.io: Secrets
- AWS: Parameter Store
- Google Cloud: Secret Manager
Next Steps
- Getting Started - Set up your environment
- Database Setup - Configure database
- Deployment - Deploy with environment variables
Need Help?
- 🌐 Notside.com - Professional configuration management
- 📧 Email: contact@notside.com