Configure Replit dev/staging/production environments with separate databases, secrets, and deployment tiers. Use when setting up multi-environment deployments, managing per-environment secrets, or implementing environment-specific Replit configurations. Trigger with phrases like "replit environments", "replit staging", "replit dev prod", "replit environment setup", "replit separate databases".
Configure development, staging, and production environments on Replit. Leverages Replit's built-in dev/prod database separation, environment-specific secrets, and deployment types. Covers the Replit-native approach (single Repl, dual databases) and the multi-Repl approach (separate Repls per environment).
Replit natively provides separate development and production databases:
Workspace "Run" button → Development database
Deployed app (.replit.app) → Production database
Both use the same DATABASE_URL env var — Replit routes automatically.
No code changes needed between environments.
For teams that need a staging environment:
Repl 1: my-app-staging → Autoscale deployment → staging.replit.app
Repl 2: my-app-prod → Reserved VM deployment → app.example.com
Each Repl has its own:
- Secrets (different API keys per environment)
- PostgreSQL database (separate data)
- Deployment configuration
- GitHub branch (staging → staging, main → production)
// src/config/environment.ts
type Environment = 'development' | 'staging' | 'production';
export function detectEnvironment(): Environment {
// Replit deployment context
if (process.env.REPL_DEPLOYMENT) {
// Check if this is the staging Repl
if (process.env.REPL_SLUG?.includes('staging')) return 'staging';
return 'production';
}
// Workspace "Run" context
if (process.env.REPL_SLUG) return 'development';
// Fallback to NODE_ENV
const env = process.env.NODE_ENV || 'development';
if (env === 'production') return 'production';
if (env === 'staging') return 'staging';
return 'development';
}
export const ENV = detectEnvironment();
export const IS_PROD = ENV === 'production';
// src/config/index.ts
import { ENV, IS_PROD } from './environment';
const configs = {
development: {
logLevel: 'debug',
corsOrigins: ['*'],
rateLimit: { windowMs: 60000, max: 1000 },
cache: { ttlMs: 5000 },
features: { debugEndpoints: true },
},
staging: {
logLevel: 'info',
corsOrigins: ['https://staging.example.com'],
rateLimit: { windowMs: 60000, max: 200 },
cache: { ttlMs: 30000 },
features: { debugEndpoints: true },
},
production: {
logLevel: 'warn',
corsOrigins: ['https://app.example.com'],
rateLimit: { windowMs: 60000, max: 100 },
cache: { ttlMs: 300000 },
features: { debugEndpoints: false },
},
};
export const config = {
env: ENV,
port: parseInt(process.env.PORT || '3000'),
...configs[ENV],
db: {
// DATABASE_URL auto-switches between dev and prod on Replit
url: process.env.DATABASE_URL,
},
};
// Validate production secrets
if (IS_PROD) {
const required = ['DATABASE_URL', 'JWT_SECRET'];
const missing = required.filter(k => !process.env[k]);
if (missing.length) {
console.error(`FATAL: Missing production secrets: ${missing.join(', ')}`);
process.exit(1);
}
}
For Single Repl (dev/prod separation):
- All secrets set once in Secrets tab
- DATABASE_URL auto-switches (Replit manages)
- Same JWT_SECRET for both (or use REPL_IDENTITY for dev)
For Multi-Repl (staging + prod):
- Each Repl has its own Secrets tab
- staging Repl: JWT_SECRET=staging-secret, API_KEY=test-key
- production Repl: JWT_SECRET=prod-secret, API_KEY=live-key
Account-level secrets (shared across all Repls):
- Settings > Secrets > Account secrets
- Useful for: monitoring tokens, shared infrastructure keys
Repository setup:
- main branch → connected to production Repl
- staging branch → connected to staging Repl
- feature branches → PR to staging first
Workflow:
1. Feature branch → PR to staging
2. Tests pass + review → merge to staging
3. Staging Repl auto-deploys → verify staging
4. Staging → PR to main
5. Merge → production Repl auto-deploys
# .github/workflows/deploy.yml