replit-multi-env-setup
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".
What this skill does
# Replit Multi-Environment Setup
## Overview
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).
## Prerequisites
- Replit Core or Teams plan (deployment access)
- PostgreSQL provisioned in Database pane
- Understanding of Replit Secrets
## Environment Strategy
### Approach 1: Single Repl, Dual Databases (Recommended)
Replit natively provides separate development and production databases:
```markdown
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.
```
### Approach 2: Multi-Repl (Staging + Production)
For teams that need a staging environment:
```markdown
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)
```
## Instructions
### Step 1: Environment Detection
```typescript
// 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';
```
### Step 2: Environment-Specific Configuration
```typescript
// 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);
}
}
```
### Step 3: Separate Secrets Per Environment
```markdown
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
```
### Step 4: GitHub Branch Strategy (Multi-Repl)
```markdown
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
```
```yaml
# .github/workflows/deploy.yml
name: Deploy Pipeline
on:
push:
branches: [staging, main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test
verify-staging:
if: github.ref == 'refs/heads/staging'
needs: test
runs-on: ubuntu-latest
steps:
- name: Wait for Replit deploy
run: sleep 60
- name: Health check staging
run: curl -sf ${{ secrets.STAGING_URL }}/health
verify-production:
if: github.ref == 'refs/heads/main'
needs: test
runs-on: ubuntu-latest
steps:
- name: Wait for Replit deploy
run: sleep 60
- name: Health check production
run: curl -sf ${{ secrets.PRODUCTION_URL }}/health
```
### Step 5: Database Migration Between Environments
```typescript
// scripts/promote-data.ts — Copy staging data to production (carefully!)
import { Pool } from 'pg';
const staging = new Pool({ connectionString: process.env.STAGING_DATABASE_URL });
const production = new Pool({ connectionString: process.env.PRODUCTION_DATABASE_URL });
async function promoteConfig() {
// Only promote configuration/reference data, never user data
const { rows: configs } = await staging.query('SELECT * FROM feature_flags');
for (const config of configs) {
await production.query(
`INSERT INTO feature_flags (key, value, updated_at)
VALUES ($1, $2, NOW())
ON CONFLICT (key) DO UPDATE SET value = $2, updated_at = NOW()`,
[config.key, config.value]
);
}
console.log(`Promoted ${configs.length} feature flags to production`);
}
```
### Step 6: Environment Indicator in UI
```typescript
// Show environment badge in development/staging
app.use((req, res, next) => {
if (!IS_PROD) {
res.setHeader('X-Environment', ENV);
}
next();
});
app.get('/api/status', (req, res) => {
res.json({
environment: ENV,
version: process.env.npm_package_version,
repl: process.env.REPL_SLUG,
});
});
```
## Error Handling
| Issue | Cause | Solution |
|-------|-------|----------|
| Wrong database in prod | Manual DATABASE_URL override | Let Replit manage DB routing |
| Staging secrets in prod | Copied secrets incorrectly | Each Repl has independent Secrets |
| GitHub sync conflict | Both Repls on same branch | Use separate branches per Repl |
| Config validation fails | Missing env-specific secret | Add secret to correct Repl's Secrets tab |
## Resources
- Replit Deployments
- [Replit Secrets](https://docs.replit.com/replit-workspace/workspace-features/secrets)
- [Deploying from GitHub](https://docs.replit.com/hosting/deployments/deploying-a-github-repository)
- [PostgreSQL Dev/Prod Databases](https://docs.replit.com/cloud-services/storage-and-databases/postgresql-on-replit)
## Next Steps
For monitoring, see `replit-observability`. For deployment, see `replit-deploy-integration`.
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.