A production-ready Express.js backend boilerplate with TypeScript, featuring a modular architecture, comprehensive security features, and best practices implementation.
- System Architecture
- Project Structure
- Configuration
- Core Features
- Implementation Guidelines
- Security
- Error Handling
- File Upload
- Caching
- Email System
- Payment Integration
- Development Guide
-
Application Layer
- Express.js server setup
- Middleware configuration
- Route management
- Error handling
-
Service Layer
- Business logic implementation
- External service integration
- Data processing
-
Data Layer
- MongoDB integration
- Redis caching
- File storage (Cloudinary)
src/
βββ app/
β βββ config/ # Environment and service configurations
β βββ errors/ # Custom error handlers and classes
β βββ helpers/ # Utility helper functions
β βββ interface/ # TypeScript type definitions
β βββ middlewares/ # Express middleware functions
β βββ modules/ # Feature-based modules
β βββ routes/ # API route definitions
β βββ shared/ # Shared utilities and constants
β βββ utils/ # Common utility functions
βββ templates/ # Email templates
βββ app.ts # Express app configuration
βββ server.ts # Server start here
Create a .env file with the following variables:
# Server Configuration
PORT=4000
NODE_ENV=development
# Database
MONGODB_URI=your_mongodb_uri
# Authentication
BCRYPT_SALT_ROUNDS=12
JWT_ACCESS_SECRET=your_access_secret
JWT_ACCESS_EXPIRES_IN=1d
JWT_REFRESH_SECRET=your_refresh_secret
JWT_REFRESH_EXPIRES_IN=7d
JWT_PASSWORD_SECRET=your_password_secret
JWT_PASSWORD_EXPIRES_IN=1h
# Redis Configuration
REDIS_URL=your_redis_url
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
REDIS_TTL=3600
REDIS_CACHE_KEY_PREFIX=app:
REDIS_TTL_ACCESS_TOKEN=3600
REDIS_TTL_REFRESH_TOKEN=604800
# Cloudinary Configuration
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
# Email Configuration
EMAIL_HOST=smtp.example.com
EMAIL_PORT=587
EMAIL_USER=your_email
EMAIL_PASS=your_password
# Payment Gateway (SSLCommerz)
STORE_ID=your_store_id
STORE_PASSWD=your_store_password
IS_LIVE=false- JWT-based authentication
- Access and refresh token mechanism
- Password reset functionality
- Role-based access control
The boilerplate implements a robust error handling system:
// Custom error class
class AppError extends Error {
statusCode: number;
status: string;
isOperational: boolean;
}
// Error handlers for different scenarios
- handleCastError: MongoDB cast errors
- handleDuplicateError: Duplicate key errors
- handleValidationError: Validation errors
- handleZodError: Schema validation errors
- handleMulterErrors: File upload errors- Cloudinary integration
- Multer middleware
- File type validation
- Size restrictions
- Automatic cleanup
- Redis-based caching
- Token storage
- Query result caching
- Cache invalidation
- HTML email templates
- Nodemailer integration
- Templates for:
- Email verification
- Password reset
// 1. Create module structure
modules/
βββ YourModule/
βββ controller.ts
βββ service.ts
βββ model.ts
βββ validation.ts
βββ routes.ts
// 2. Implement controller
export const createItem = catchAsync(async (req: Request, res: Response) => {
const result = await YourService.createItem(req.body);
sendResponse(res, {
statusCode: httpStatus.CREATED,
success: true,
data: result
});
});
// 3. Add routes
router.post('/', validateRequest(YourValidation.createSchema), createItem);// Authentication middleware
router.use(auth());
// File upload middleware
router.post('/upload',
multerMiddleware.single('file'),
uploadController
);
// Request validation
router.post('/create',
validateRequest(validationSchema),
controller
);try {
// Your code
} catch (error) {
throw new AppError('Error message', httpStatus.BAD_REQUEST);
}// Configure multer
const upload = multer({
storage: cloudinaryStorage,
limits: {
fileSize: 5 * 1024 * 1024 // 5MB
}
});
// Use in route
router.post('/upload', upload.single('file'), uploadController);// Cache data with TTL
await cacheData(
'cache-key',
{ data: 'value' },
3600 // TTL in seconds
);
// Retrieve cached data
const cachedData = await getCachedData('cache-key');
// Delete cached data by pattern
await deleteCachedData('pattern*');
// Clear all cached data
await clearAllCachedData();The Redis caching system provides the following utilities:
-
cacheData
- Caches data with a specified TTL (Time To Live)
- Automatically serializes data to JSON
- Handles errors gracefully with logging
-
getCachedData
- Retrieves cached data by key
- Automatically deserializes JSON data
- Returns null if data doesn't exist or on error
-
deleteCachedData
- Deletes cached data matching a pattern
- Supports wildcard patterns
- Handles multiple key deletion
-
clearAllCachedData
- Clears all cached data from Redis
- Useful for cache invalidation
Example usage in a service:
// In your service file
const getData = async (id: string) => {
// Try to get from cache first
const cachedData = await getCachedData(`data:${id}`);
if (cachedData) {
return cachedData;
}
// If not in cache, get from database
const data = await YourModel.findById(id);
// Cache the result
await cacheData(`data:${id}`, data, 3600); // Cache for 1 hour
return data;
};- JWT token-based authentication
- Refresh token rotation
- Token blacklisting
- Password hashing with bcrypt
- Zod schema validation
- Input sanitization
- Type checking
- File type validation
- Size restrictions
- Secure storage
- Automatic cleanup
- CORS protection
- Rate limiting
- XSS protection
- SQL injection prevention
Located in templates/:
verification-email.htmlreset-password-email.html
await sendEmail({
to: user.email,
subject: 'Email Verification',
html: verificationEmailTemplate
});const sslcommerz = new SSLCommerz(
config.store_id,
config.store_passwd,
config.is_live === 'true'
);
// Create payment session
const paymentSession = await sslcommerz.initiatePayment({
// payment details
});# Install dependencies
npm install
# Create .env file
cp .env.example .env
# Start development server
npm run devnpm run build# Build and run with Docker
docker-compose up --build-
Code Organization
- Follow modular architecture
- Keep controllers thin
- Implement proper separation of concerns
-
Error Handling
- Use custom error classes
- Implement proper error logging
- Handle all possible error scenarios
-
Security
- Validate all inputs
- Implement proper authentication
- Use environment variables
- Follow security best practices
-
Performance
- Implement caching where appropriate
- Optimize database queries
- Use proper indexing
- Express.js Documentation
- TypeScript Documentation
- MongoDB Documentation
- Redis Documentation
- Cloudinary Documentation
- SSLCommerz Documentation
- Fork the repository
- Create your feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request
ISC License