A production-ready Express.js starter template with TypeScript, featuring authentication, authorization, comprehensive error handling, and modular architecture.
- β TypeScript - Type safety and better developer experience
- β Modular Architecture - Feature-based folder structure
- β Authentication - JWT-based auth with access and refresh tokens
- β Authorization - Role-based access control (RBAC)
- β Validation - Request validation using Zod
- β Error Handling - Centralized error handling with custom error classes
- β Logging - Winston logger with multiple transports
- β Security - Helmet, CORS, rate limiting
- β Environment Config - Type-safe environment variables with validation
- Node.js (v18 or higher)
- npm or yarn or pnpm
- Clone or use the template
cd express-ts-starter- Install dependencies
npm install- Set up environment variables
cp .env.example .envEdit .env and update the values:
NODE_ENV=development
PORT=4000
API_VERSION=v1
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production-minimum-32-chars
JWT_REFRESH_SECRET=your-super-secret-refresh-key-change-this-in-production-minimum-32-chars
JWT_EXPIRES_IN=15m
JWT_REFRESH_EXPIRES_IN=7d
ALLOWED_ORIGINS=http://localhost:4000,http://localhost:5173- Create logs directory
mkdir logsnpm run devnpm run build
npm startsrc/
βββ config/ # Configuration files
β βββ env.ts # Environment variables with validation
β βββ logger.ts # Winston logger configuration
βββ modules/ # Feature modules
β βββ auth/ # Authentication module
β β βββ auth.controller.ts
β β βββ auth.service.ts
β β βββ auth.routes.ts
β β βββ auth.validation.ts
β βββ users/ # Users module
β βββ user.controller.ts
β βββ user.service.ts
β βββ user.routes.ts
β βββ user.validation.ts
βββ shared/ # Shared resources
β βββ database/ # Database models/repositories
β βββ errors/ # Custom error classes
β βββ middleware/ # Express middleware
β βββ types/ # TypeScript types and interfaces
β βββ utils/ # Utility functions
βββ routes/ # Route definitions
βββ app.ts # Express app configuration
βββ server.ts # Server entry point
USER- Regular userMODERATOR- Moderator with elevated permissionsADMIN- Administrator with full access
- Register:
POST /api/v1/auth/register - Login:
POST /api/v1/auth/login- Returns access and refresh tokens - Refresh Token:
POST /api/v1/auth/refresh- Get new access token - Get Profile:
GET /api/v1/auth/profile- Requires authentication - Logout:
POST /api/v1/auth/logout- Invalidate token
Use the authorize middleware to protect routes:
router.get('/admin-only',
authenticate,
authorize(UserRole.ADMIN),
controller.method
);GET /api/v1/health
POST /api/v1/auth/register # Register new user
POST /api/v1/auth/login # Login user
POST /api/v1/auth/refresh # Refresh access token
GET /api/v1/auth/profile # Get current user profile (Protected)
POST /api/v1/auth/logout # Logout (Protected)
GET /api/v1/users # Get all users (Admin)
GET /api/v1/users/:id # Get user by ID (Admin)
PATCH /api/v1/users/me # Update current user (Protected)
PATCH /api/v1/users/:id/role # Update user role (Admin)
DELETE /api/v1/users/:id # Delete user (Admin)
curl -X POST http://localhost:4000/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "Password123",
"firstName": "John",
"lastName": "Doe"
}'curl -X POST http://localhost:4000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "Password123"
}'curl -X GET http://localhost:4000/api/v1/auth/profile \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"- Email: Valid email format
- Password: Minimum 8 characters, must contain uppercase, lowercase, and number
- First/Last Name: Minimum 2 characters
- Minimum 8 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one number
- Helmet - Sets security-related HTTP headers
- CORS - Configurable cross-origin resource sharing
- Rate Limiting - Prevents abuse (100 requests per 15 minutes by default)
- Password Hashing - Bcrypt with configurable rounds
- JWT - Secure token-based authentication
- Input Validation - Zod schema validation for all inputs
The application uses custom error classes for consistent error responses:
BadRequestError(400)UnauthorizedError(401)ForbiddenError(403)NotFoundError(404)ConflictError(409)ValidationError(422)InternalServerError(500)
Example error response:
{
"success": false,
"message": "User with this email already exists"
}Winston logger with multiple levels:
error- Error messageswarn- Warning messagesinfo- Informational messageshttp- HTTP request logsdebug- Debug messages (development only)
Logs are saved to:
logs/error.log- Error logs onlylogs/all.log- All logs
Currently uses an in-memory database for demonstration. Replace src/shared/database/user.db.ts with your preferred database:
- PostgreSQL with Drizzle or TypeORM
- MongoDB with Mongoose
- MySQL with TypeORM
- Set
NODE_ENV=productionin your environment - Update
JWT_SECRETandJWT_REFRESH_SECRETwith strong random values - Configure
ALLOWED_ORIGINSfor your frontend domains - Set up a real database
- Build the application:
npm run build - Start the server:
npm start
- Create a new folder in
src/modules/ - Add controller, service, routes, and validation files
- Register routes in
src/routes/index.ts
Example structure:
src/modules/products/
βββ product.controller.ts
βββ product.service.ts
βββ product.routes.ts
βββ product.validation.ts
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Open a pull request
MIT
Built with best practices for production-ready Express.js applications.