How to implement multi-environment deployment (development, testing, production) on Vercel?
Implementing multi-environment deployment on Vercel is an important practice in modern software development, allowing developers to test and deploy code in different environments to ensure code quality and stability. Here's a detailed implementation guide.
Vercel Environment Concepts
1. Three Main Environments
Production:
- Deployed to main domain
- Uses production database and API
- URL:
https://your-project.vercel.appor custom domain - Trigger condition: Merged to main branch
Preview:
- Generates unique URL for each branch or PR
- Uses test database and API
- URL:
https://your-project-branch.vercel.app - Trigger condition: Create or update Pull Request
Development:
- Used for local development
- Uses development database and API
- Accessed via Vercel CLI
- For local testing and debugging
Environment Configuration
1. Environment Variable Management
Configure in Dashboard:
- Go to project settings
- Select "Environment Variables"
- Add environment variables
- Select applicable environment (Production, Preview, Development)
Configuration Example:
| Variable Name | Production | Preview | Development |
|---|---|---|---|
DATABASE_URL | postgres://prod-db... | postgres://test-db... | postgres://dev-db... |
API_URL | https://api.example.com | https://api-test.example.com | http://localhost:3001 |
NODE_ENV | production | preview | development |
SENTRY_DSN | prod-dsn | test-dsn | dev-dsn |
Configure via CLI:
bash# Add production environment variable vercel env add DATABASE_URL production # Enter production database URL # Add preview environment variable vercel env add DATABASE_URL preview # Enter test database URL # Add development environment variable vercel env add DATABASE_URL development # Enter development database URL
2. Environment-Specific Configuration
Using vercel.json:
json{ "version": 2, "buildCommand": "npm run build", "outputDirectory": "dist", "env": { "BUILD_TIME": "${NOW}" }, "build": { "env": { "BUILD_ENV": "production" } } }
Using Environment Variables in Code:
javascript// Get environment const environment = process.env.NODE_ENV || 'development'; // Configure based on environment const config = { production: { apiUrl: 'https://api.example.com', databaseUrl: process.env.DATABASE_URL, enableAnalytics: true, }, preview: { apiUrl: 'https://api-test.example.com', databaseUrl: process.env.DATABASE_URL, enableAnalytics: false, }, development: { apiUrl: 'http://localhost:3001', databaseUrl: 'postgres://localhost:5432/dev', enableAnalytics: false, }, }; const currentConfig = config[environment] || config.development;
Branch Strategy
1. Git Flow Branch Model
Branch Structure:
shellmain (production) └── develop (development) ├── feature/user-authentication ├── feature/payment-gateway └── bugfix/login-error
Configure Deployment Rules:
javascript// vercel.json { "git": { "deploymentEnabled": { "main": true, "develop": true, "feature/*": true, "hotfix/*": true } } }
2. Trunk-Based Development
Branch Structure:
shellmain (main branch) ├── feature-branch-1 ├── feature-branch-2 └── hotfix-branch
Configuration:
javascript{ "git": { "deploymentEnabled": { "main": true, "feature-*": true, "hotfix-*": true } } }
Deployment Process
1. Development Environment Deployment
Local Development:
bash# Install Vercel CLI npm install -g vercel # Login vercel login # Pull environment variables vercel env pull .env.local # Start local development server vercel dev # Or use npm scripts npm run dev
Development Environment Configuration:
javascript// .env.local DATABASE_URL=postgres://localhost:5432/dev API_URL=http://localhost:3001 NODE_ENV=development
2. Preview Environment Deployment
Create Pull Request:
- Create feature branch
- Push code to remote repository
- Create Pull Request
- Vercel automatically creates preview deployment
- Get preview URL for testing
Preview Deployment URL:
- Format:
https://your-project-branch-name.vercel.app - Example:
https://myapp-feature-auth.vercel.app
Configure Preview Environment:
javascript// vercel.json { "preview": { "env": { "PREVIEW_MODE": "true" } } }
3. Production Environment Deployment
Merge to Main Branch:
- Code review passes
- Merge Pull Request to main branch
- Vercel automatically triggers production deployment
- Deploy to production domain
Manual Production Deployment:
bash# Deploy to production environment vercel --prod # Or use specific branch vercel --prod --scope your-team
Production Environment Configuration:
javascript// vercel.json { "production": { "env": { "PRODUCTION_MODE": "true" } } }
Database Management
1. Multi-Environment Databases
Using Different Databases:
javascript// lib/database.js const { PrismaClient } = require('@prisma/client'); let prisma; if (process.env.NODE_ENV === 'production') { prisma = new PrismaClient({ datasources: { db: { url: process.env.DATABASE_URL, }, }, }); } else if (process.env.NODE_ENV === 'preview') { prisma = new PrismaClient({ datasources: { db: { url: process.env.DATABASE_URL, }, }, }); } else { prisma = new PrismaClient({ datasources: { db: { url: 'postgres://localhost:5432/dev', }, }, }); } module.exports = prisma;
2. Database Migrations
Environment-Specific Migrations:
bash# Development environment migration npm run migrate:dev # Preview environment migration npm run migrate:preview # Production environment migration npm run migrate:prod
Configure Migration Scripts:
json{ "scripts": { "migrate:dev": "prisma migrate dev", "migrate:preview": "prisma migrate deploy", "migrate:prod": "prisma migrate deploy" } }
Testing Strategy
1. Environment-Specific Testing
Development Environment Testing:
javascript// tests/setup.js const { execSync } = require('child_process'); if (process.env.NODE_ENV === 'development') { // Setup test database execSync('npm run db:setup:test'); // Run unit tests execSync('npm run test:unit'); }
Preview Environment Testing:
javascript// tests/integration.js describe('Integration Tests', () => { beforeAll(() => { // Skip certain tests in preview environment if (process.env.NODE_ENV === 'preview') { console.log('Skipping expensive integration tests in preview'); } }); test('API integration', async () => { // Integration tests }); });
Production Environment Testing:
javascript// tests/smoke.js describe('Smoke Tests', () => { test('Production health check', async () => { if (process.env.NODE_ENV === 'production') { const response = await fetch('https://your-project.vercel.app/health'); expect(response.status).toBe(200); } }); });
2. Automated Testing
Configure CI/CD:
yaml# .github/workflows/test.yml name: Test on: push: branches: [main, develop] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: '18' - run: npm ci - run: npm run test - run: npm run lint
Monitoring and Logging
1. Environment-Specific Monitoring
Configure Monitoring:
javascript// lib/monitoring.js const Sentry = require('@sentry/node'); if (process.env.NODE_ENV === 'production') { Sentry.init({ dsn: process.env.SENTRY_DSN, environment: 'production', tracesSampleRate: 1.0, }); } else if (process.env.NODE_ENV === 'preview') { Sentry.init({ dsn: process.env.SENTRY_DSN, environment: 'preview', tracesSampleRate: 0.5, }); } else { // Disable Sentry in development console.log('Monitoring disabled in development'); }
2. Log Management
Environment-Specific Logging:
javascript// lib/logger.js const winston = require('winston'); const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.json(), transports: [ new winston.transports.Console({ format: winston.format.simple(), }), ], }); if (process.env.NODE_ENV === 'production') { logger.add(new winston.transports.File({ filename: 'error.log', level: 'error' })); logger.add(new winston.transports.File({ filename: 'combined.log' })); } module.exports = logger;
Best Practices
1. Environment Isolation
Strict Environment Isolation:
- Use independent databases for each environment
- Use independent API endpoints for each environment
- Use independent storage for each environment
- Avoid data confusion between environments
Environment Naming Conventions:
- Use clear environment names
- Clearly identify environment in code
- Log environment information
2. Configuration Management
Using Configuration Files:
javascript// config/index.js const config = { production: { apiUrl: process.env.API_URL, databaseUrl: process.env.DATABASE_URL, enableAnalytics: true, logLevel: 'error', }, preview: { apiUrl: process.env.API_URL, databaseUrl: process.env.DATABASE_URL, enableAnalytics: false, logLevel: 'warn', }, development: { apiUrl: 'http://localhost:3001', databaseUrl: 'postgres://localhost:5432/dev', enableAnalytics: false, logLevel: 'debug', }, }; const environment = process.env.NODE_ENV || 'development'; module.exports = config[environment];
3. Security
Environment Variable Security:
- Don't hardcode sensitive information in code
- Use environment variables for secrets
- Regularly rotate secrets
- Limit environment variable access permissions
Production Environment Protection:
- Limit production environment access
- Use strong passwords and secrets
- Enable two-factor authentication
- Regularly audit access logs
4. Deployment Strategy
Progressive Deployment:
- Deploy to preview environment first
- Conduct thorough testing
- Deploy to production environment
- Monitor production environment
- If issues, quick rollback
Rollback Strategy:
- Keep all historical deployments
- Quick rollback to stable version
- Record rollback reasons
- Analyze root cause of issues
Troubleshooting
1. Environment Variable Issues
Problem: Environment variables not taking effect
Solutions:
- Check if environment variables are correctly configured
- Confirm environment variable name spelling is correct
- Redeploy project
- Check applicable environment for environment variables
2. Deployment Failures
Problem: Specific environment deployment fails
Solutions:
- View deployment logs
- Check environment variable configuration
- Verify dependency installation
- Check build command
3. Database Connection Issues
Problem: Cannot connect to database
Solutions:
- Verify database URL configuration
- Check database access permissions
- Confirm database service running status
- Test database connection
Summary
Key points for implementing multi-environment deployment on Vercel:
- Environment Isolation: Each environment uses independent resources and configuration
- Environment Variables: Correctly configure and manage environment variables
- Branch Strategy: Choose appropriate Git branch model
- Automation: Leverage CI/CD to automate deployment process
- Monitoring: Implement comprehensive monitoring and logging
- Security: Protect production environment and sensitive information
- Testing: Conduct thorough testing in each environment
By following these best practices, you can establish a reliable, efficient multi-environment deployment process on Vercel, improving code quality and deployment efficiency.