Deployxa Best Practices
Comprehensive best practices for deploying, managing, and scaling applications on Deployxa.
Repository Structure
Recommended Structure
my-app/
├── src/ # Source code
├── public/ # Static assets
├── tests/ # Test files
├── .env.example # Environment template
├── .gitignore # Git ignore rules
├── .dockerignore # Docker ignore rules
├── README.md # Project documentation
├── package.json # Dependencies (Node.js)
├── requirements.txt # Dependencies (Python)
├── composer.json # Dependencies (PHP)
└── Dockerfile # Custom Docker config (optional)
Best Practices
✅ Keep it clean:
- Remove unnecessary files
- Exclude build artifacts
- Don't commit dependencies
- Use
.gitignoreproperly
✅ Document everything:
- Clear README with setup instructions
- API documentation
- Environment variable documentation
- Deployment instructions
✅ Use environment files:
.env.examplefor template- Never commit
.envfiles - Document all required variables
- Use different values per environment
✅ Organize code:
- Follow framework conventions
- Separate concerns
- Use consistent naming
- Keep related files together
Docker Optimization
Multi-Stage Builds
Use multi-stage builds to reduce image size:
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:18-alpine AS runner
WORKDIR /app
COPY /app/dist ./dist
COPY /app/node_modules ./node_modules
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]
Benefits:
- 60-80% smaller images
- Faster deployments
- Better security
- Reduced bandwidth
Optimize Layers
Order Dockerfile commands for better caching:
# ✅ Good: Dependencies first (cached)
COPY package*.json ./
RUN npm ci
COPY . .
# ❌ Bad: Code first (invalidates cache)
COPY . .
COPY package*.json ./
RUN npm ci
Use Alpine Base Images
Alpine images are smaller and more secure:
# ✅ Good: Alpine (5-10MB)
FROM node:18-alpine
# ❌ Bad: Full image (300MB+)
FROM node:18
Minimize Dependencies
Install only what you need:
# ✅ Good: Production only
RUN npm ci --only=production
# ❌ Bad: All dependencies
RUN npm install
Use .dockerignore
Exclude unnecessary files:
node_modules
.git
.env
*.log
tests
docs
Secrets Management
Use Environment Variables
Never hardcode secrets:
// ❌ Bad: Hardcoded
const apiKey = 'sk_test_1234567890';
// ✅ Good: Environment variable
const apiKey = process.env.API_KEY;
Encrypt Sensitive Data
Enable encryption for secrets:
# Deployxa dashboard
Project → Environment → Add Variable → Enable Encryption
Rotate Secrets Regularly
Rotation schedule:
- API keys: Every 90 days
- Database passwords: Every 180 days
- JWT secrets: Every 365 days
- OAuth secrets: Every 180 days
Rotation process:
- Generate new secret
- Add new environment variable
- Deploy application
- Verify application works
- Remove old variable
- Deploy again
Use Different Secrets Per Environment
# Production
DATABASE_URL=postgresql://prod-host:5432/db
API_KEY=prod_key_123
# Preview
DATABASE_URL=postgresql://preview-host:5432/db
API_KEY=preview_key_123
# Development
DATABASE_URL=postgresql://localhost:5432/db
API_KEY=dev_key_123
Never Commit Secrets
Add to .gitignore:
.env
.env.local
.env.production
*.key
*.pem
Scaling Strategies
Right-Size Resources
Monitor and adjust based on usage:
Small apps (< 100 req/min):
- 0.5 CPU, 512MB RAM
Medium apps (100-1000 req/min):
- 1.0 CPU, 1024MB RAM
Large apps (> 1000 req/min):
- 2.0+ CPU, 2048MB+ RAM
Enable Auto-Scaling
Configure auto-scaling for variable traffic:
{
"minContainers": 2,
"maxContainers": 10,
"triggers": [
{
"metric": "cpu_usage",
"threshold": 70,
"action": "scale_up"
}
]
}
Use Scale-to-Zero
For low-traffic applications:
- Saves costs when idle
- Automatic wake-up on traffic
- 15-minute idle timeout
Monitor Resource Usage
Track usage patterns:
- CPU usage trends
- Memory usage patterns
- Bandwidth consumption
- Request rates
Plan for Traffic Spikes
Strategies:
- Pre-scale before known events
- Use CDN for static assets
- Enable caching
- Use queue for background jobs
Performance Optimization
Enable Caching
Application caching:
// Redis cache
const cache = require('redis').createClient();
app.get('/data', async (req, res) => {
const cached = await cache.get('data');
if (cached) return res.json(JSON.parse(cached));
const data = await fetchData();
await cache.setEx('data', 3600, JSON.stringify(data));
res.json(data);
});
CDN caching:
// Cache headers
app.get('/static/*', (req, res) => {
res.setHeader('Cache-Control', 'public, max-age=31536000');
res.sendFile(req.path);
});
Optimize Database Queries
Use indexes:
CREATE INDEX idx_users_email ON users(email);
Avoid N+1 queries:
// ❌ Bad: N+1 queries
const users = await User.findAll();
for (const user of users) {
const posts = await Post.findByUserId(user.id);
}
// ✅ Good: Eager loading
const users = await User.findAll({
include: ['posts']
});
Use connection pooling:
const pool = new Pool({
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
Enable Compression
Gzip compression:
const compression = require('compression');
app.use(compression());
Brotli compression:
const express = require('express');
const app = express();
app.use((req, res, next) => {
if (req.headers['accept-encoding']?.includes('br')) {
res.setHeader('Content-Encoding', 'br');
}
next();
});
Optimize Images
Use modern formats:
- WebP instead of JPEG/PNG
- AVIF for better compression
- SVG for icons and logos
Resize images:
const sharp = require('sharp');
await sharp(input)
.resize(800, 600)
.webp({ quality: 80 })
.toFile(output);
Use CDN
Serve static assets via CDN:
// Configure CDN
app.use('/static', express.static('public', {
maxAge: '1y',
etag: false
}));
Production Deployments
Pre-Deployment Checklist
✅ Code quality:
- All tests passing
- No linting errors
- Code reviewed
- Documentation updated
✅ Configuration:
- Environment variables set
- Database configured
- Domains verified
- SSL certificates active
✅ Monitoring:
- Health checks configured
- Alerts set up
- Logging enabled
- Metrics tracking
✅ Security:
- Secrets encrypted
- HTTPS enforced
- Security headers enabled
- Dependencies updated
Deployment Strategy
Rolling updates:
- Zero downtime
- Gradual rollout
- Instant rollback
- Health checks
Blue/Green deployments:
- Full environment switch
- Instant rollback
- Complete testing
- Higher resource usage
Rollback Plan
When to rollback:
- Error rate > 5%
- Response time > 3s
- Critical errors
- Security vulnerabilities
Rollback process:
- Identify issue
- Trigger rollback
- Verify health
- Investigate root cause
- Fix and redeploy
Monitoring Setup
Health checks:
app.get('/health', (req, res) => {
res.status(200).json({
status: 'healthy',
timestamp: new Date().toISOString()
});
});
Metrics to track:
- Request rate
- Error rate
- Response time
- CPU usage
- Memory usage
- Bandwidth
Alerts:
- CPU > 80%
- Memory > 85%
- Error rate > 1%
- Response time > 2s
Security Best Practices
Input Validation
Server-side validation:
const Joi = require('joi');
const schema = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().min(8).required()
});
app.post('/register', (req, res) => {
const { error } = schema.validate(req.body);
if (error) return res.status(400).json({ error });
// Process registration
});
Client-side validation:
// React with Formik
import * as Yup from 'yup';
const validationSchema = Yup.object({
email: Yup.string().email().required(),
password: Yup.string().min(8).required()
});
Use Parameterized Queries
Prevent SQL injection:
// ✅ Good: Parameterized
const result = await pool.query(
'SELECT * FROM users WHERE email = $1',
[email]
);
// ❌ Bad: String concatenation
const result = await pool.query(
`SELECT * FROM users WHERE email = '${email}'`
);
Enable Security Headers
Recommended headers:
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
Use HTTPS Only
Enforce HTTPS:
// Express.js
app.use((req, res, next) => {
if (req.header('x-forwarded-proto') !== 'https') {
return res.redirect(`https://${req.header('host')}${req.url}`);
}
next();
});
Implement Rate Limiting
Prevent abuse:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP'
});
app.use('/api/', limiter);
Keep Dependencies Updated
Regular updates:
# Check for vulnerabilities
npm audit
# Fix vulnerabilities
npm audit fix
# Update dependencies
npm update
Monitoring Best Practices
Set Up Health Checks
Application health:
app.get('/health', (req, res) => {
// Check database
db.query('SELECT 1', (err) => {
if (err) return res.status(500).json({ status: 'unhealthy' });
res.status(200).json({ status: 'healthy' });
});
});
Configure Alerts
Alert thresholds:
- CPU > 80% for 5 minutes
- Memory > 85% for 5 minutes
- Error rate > 1% for 5 minutes
- Response time > 2s for 5 minutes
Notification channels:
- Email for all alerts
- Slack for critical alerts
- SMS for emergency alerts
Monitor Key Metrics
Application metrics:
- Request rate
- Error rate
- Response time (P50, P95, P99)
- Throughput
Infrastructure metrics:
- CPU usage
- Memory usage
- Disk I/O
- Network I/O
Business metrics:
- Active users
- Conversion rate
- Revenue
- Customer satisfaction
Use Structured Logging
JSON logging:
const winston = require('winston');
const logger = winston.createLogger({
format: winston.format.json(),
transports: [
new winston.transports.Console()
]
});
logger.info('User logged in', {
userId: 123,
ip: req.ip,
timestamp: new Date()
});
Review Logs Regularly
Daily review:
- Error patterns
- Performance trends
- Security events
- User activity
Weekly review:
- Usage trends
- Resource optimization
- Cost analysis
- Security posture
Cost Optimization
Right-Size Resources
Monitor usage:
- Track CPU/RAM usage
- Identify underutilized resources
- Adjust limits accordingly
Avoid over-provisioning:
- Start with minimum resources
- Scale up as needed
- Use auto-scaling
Enable Scale-to-Zero
For low-traffic apps:
- Saves costs when idle
- Automatic wake-up
- 15-minute timeout
Use Build Cache
Faster builds:
- Enable build cache
- Cache dependencies
- Reuse build artifacts
Optimize Bandwidth
Reduce bandwidth:
- Enable compression
- Use CDN
- Optimize images
- Minify assets
Monitor Costs
Track spending:
- Review invoices monthly
- Set budget alerts
- Identify cost drivers
- Optimize regularly
Troubleshooting Best Practices
Systematic Approach
-
Identify the problem:
- Check logs
- Review metrics
- Reproduce issue
-
Isolate the cause:
- Check recent changes
- Review dependencies
- Test components
-
Implement fix:
- Apply solution
- Test thoroughly
- Deploy carefully
-
Verify resolution:
- Monitor metrics
- Check logs
- Confirm fix
Use Logs Effectively
Search logs:
# Search for errors
grep "error" logs/app.log
# Filter by time
grep "2024-01-15" logs/app.log
# Count errors
grep -c "error" logs/app.log
Monitor During Troubleshooting
Watch metrics:
- CPU usage
- Memory usage
- Error rate
- Response time
Check logs in real-time:
tail -f logs/app.log
Document Solutions
Create runbooks:
- Common issues
- Step-by-step fixes
- Prevention measures
- Contact information
Learn from Incidents
Post-mortem process:
- Timeline reconstruction
- Root cause analysis
- Impact assessment
- Lessons learned
- Action items
- Documentation update
Related Topics
Resources
Need Help? Contact support@deployxa.com or join our community Discord.