A minimal REST API starter built with:
- Node.js + TypeScript
- Express (v5)
- TypeORM (0.3)
- PostgreSQL (via Docker Compose)
The project exposes a sample endpoint that returns a mock list of employees and includes a TypeORM configuration with a User entity and migration scripts.
- Prerequisites
- Getting Started
- Clone and install
- Start PostgreSQL with Docker
- Configure environment
- Run the server
- PM2 (Process Manager)
- RabbitMQ (Message Queue Consumer)
- Scripts
- Configuration (Environment Variables)
- Database and Migrations
- API
- Troubleshooting
- Node.js 18+ and npm
- Docker + Docker Compose (optional, recommended for PostgreSQL)
npm installA ready-to-use docker-compose.yml file is provided.
# In PowerShell or your shell of choice
docker compose up -dThis starts a PostgreSQL 16 instance with:
- Host: localhost
- Port: 5432
- User: user
- Password: password
- Database: db-webkit
Data will persist in the local postgres-data directory.
The app reads database settings from environment variables. Defaults match the provided docker-compose.
PowerShell example (Windows):
$env:DB_HOST = "localhost"
$env:DB_PORT = "5432"
$env:DB_USER = "user"
$env:DB_PASSWORD = "password"
$env:DB_NAME = "db-webkit"
$env:DB_LOGGING = "false" # set to "true" to see SQL logs
$env:DB_SYNCHRONIZE = "false" # set to "true" for dev-only auto schema syncBash example (macOS/Linux):
export DB_HOST=localhost
export DB_PORT=5432
export DB_USER=user
export DB_PASSWORD=password
export DB_NAME=db-webkit
export DB_LOGGING=false
export DB_SYNCHRONIZE=falseDevelopment (with tsx):
npm run devOr simply:
npm startThe server listens on port 3002 by default (see src/app.ts if you changed it).
PM2 is a production process manager for Node.js applications with a built-in load balancer. This project includes a pre-configured ecosystem.config.cjs file for easy deployment and process management.
Install PM2 globally:
npm install -g pm2Before using PM2, build the project:
npm run buildStart the application with PM2:
# Production environment
npm run pm2
# Local environment
npm run pm2:local
# Development environment
npm run pm2:devThe ecosystem.config.cjs file configures PM2 with:
- Cluster Mode: Runs multiple instances (one per CPU core) for better performance
- Max Memory Restart: Automatically restarts if memory exceeds 512MB
- Environment Variables: Pre-configured for production, local, and development environments
- Log Management: Stores logs in
./logs/pm2-error.logand./logs/pm2-out.log
Start Application:
npm run pm2 # Start in production mode
npm run pm2:local # Start in local mode
npm run pm2:dev # Start in development modeProcess Management:
npm run pm2:stop # Stop the application
npm run pm2:restart # Restart the application
npm run pm2:delete # Stop and remove from PM2Monitoring:
npm run pm2:list # List all PM2 processes
npm run pm2:logs # Display real-time logs
npm run pm2:monitor # Open PM2 monitoring dashboardYou can also use PM2 directly:
# Start with specific environment
pm2 start ecosystem.config.cjs --env production
pm2 start ecosystem.config.cjs --env local
pm2 start ecosystem.config.cjs --env development
# Monitor processes
pm2 status # Show process status
pm2 logs webkit-app # Show logs for webkit-app
pm2 monit # Open monitoring dashboard
# Process management
pm2 reload webkit-app # Reload with zero downtime
pm2 restart webkit-app # Restart the application
pm2 stop webkit-app # Stop the application
pm2 delete webkit-app # Remove from PM2
# View detailed info
pm2 show webkit-app # Show detailed process information
pm2 describe webkit-app # Alias for showProduction (--env production):
NODE_ENV=production- Uses your system's environment variables for database and other configs
Local (--env local):
NODE_ENV=localPORT=3002- Database:
localhost:5432/db-webkit - Loki logging enabled (
http://localhost:3100) DB_SYNCHRONIZE=true
Development (--env development):
NODE_ENV=development- Same configuration as local mode
To configure PM2 to start on system boot:
# Generate startup script
pm2 startup
# Save current process list
pm2 save
# Disable startup (if needed)
pm2 unstartupPM2 logs are stored in:
- Error logs:
./logs/pm2-error.log - Output logs:
./logs/pm2-out.log
View and manage logs:
pm2 logs # Stream all logs
pm2 logs webkit-app # Stream logs for webkit-app
pm2 flush # Clear all logs
pm2 reloadLogs # Reload log configurationThe cluster mode configuration automatically:
- Spawns one instance per CPU core (
instances: 'max') - Load balances incoming requests across instances
- Provides zero-downtime reloads
- Restarts crashed processes automatically
Application won't start:
- Ensure you've run
npm run buildfirst - Check logs:
npm run pm2:logs - Verify database is running:
docker compose ps
High memory usage:
- Check PM2 status:
npm run pm2:list - Adjust
max_memory_restartinecosystem.config.cjsif needed - Investigate memory leaks in application code
PM2 command not found:
- Install PM2 globally:
npm install -g pm2 - Or use npx:
npx pm2 <command>
The project includes optional RabbitMQ consumer integration for processing asynchronous messages from queues and exchanges.
- Start RabbitMQ (included in docker-compose):
docker compose up -d rabbitmq- Enable in your environment:
RABBITMQ_ENABLED=true
RABBITMQ_URL=amqp://admin:admin@localhost:5672- Access Management UI: http://localhost:15672
- Username:
admin - Password:
admin
- Username:
Environment variables:
RABBITMQ_ENABLED(true|false, default:false) - Enable/disable RabbitMQ integrationRABBITMQ_URL(default:amqp://admin:admin@localhost:5672) - Connection URL
The project includes example consumers in src/services/rabbitmq-consumer-examples.ts:
// Consume from a simple queue
await rabbitMQConsumerService.consumeQueue('user.notifications', (message) => {
console.log('Processing:', message)
})
// Consume from exchange with routing pattern
await rabbitMQConsumerService.consumeExchange(
'events',
'user.*', // matches user.created, user.updated, etc.
'user-events-queue',
(message) => {
console.log('User event:', message)
},
'topic'
)Via Management UI:
- Open http://localhost:15672
- Go to Queues tab
- Click on your queue (e.g.,
user.notifications) - Use Publish message section to send a test message
Check Health Status:
curl http://localhost:3002/ready
# Shows RabbitMQ connection status in responseFor complete documentation, see docs/RABBITMQ.md.
Note: The server will start successfully even if RabbitMQ is unavailable. Set RABBITMQ_ENABLED=false if you don't need message queue functionality.
Defined in package.json:
npm run dev/npm start— start the server with tsx:tsx src/main.tsnpm run build— compile TypeScript to JavaScript viatscnpm run migration:generate— generate a migration from current model changesnpm run migration:run— run pending migrationsnpm run migration:revert— revert the last migration
Migration workflow example:
# Create an empty migration file
npm run migration:create -- src/migration/MyMigration
# Generate migration from entity changes
npm run migration:generate -- src/migration/add-email
# Run pending migrations
npm run migration:run
# Revert last migration
npm run migration:revertThe TypeORM DataSource (src\integrations\data-source.ts) uses:
DB_HOST(default:localhost)DB_PORT(default:5432)DB_USER(default:user)DB_PASSWORD(default:password)DB_NAME(default:db-webkit)DB_LOGGING(true|false, default:false)DB_SYNCHRONIZE(true|false, default:false)
RabbitMQ configuration:
RABBITMQ_ENABLED(true|false, default:false)RABBITMQ_URL(default:amqp://admin:admin@localhost:5672)
Note: Keep DB_SYNCHRONIZE=false in non-development environments. Use migrations to manage schema.
npm run migration:generate -- src/migration/add-email
- DataSource file:
src/integrations/data-source.ts - Entities: currently
src/entity/User.ts - Migrations directory:
src/migration/*.ts(create this folder when generating migrations)
Typical flow (examples):
# Generate migration from entity changes
npm run migration:generate -- src/migration/<MigrationName>
# Run migrations
npm run migration:run
# Revert last migration
npm run migration:revertIf you prefer quick development without migrations, you can temporarily set DB_SYNCHRONIZE=true (not recommended for production) to let TypeORM auto-sync the schema based on entities.
Base URL (default): http://localhost:3002
- GET
/— returns a mock list of employees- Controller:
src/controllers/EmployController.ts - Repository:
src/repositories/EmployeeRepository.ts
- Controller:
Example request:
curl http://localhost:3002/Example response:
[{ "id": 1 }, { "id": 2 }]src/app.ts— Express app, sets port and mounts routessrc/main.ts— App bootstrap and database initializationsrc/routes/employee.ts— Router exposing GET/src/controllers/EmployController.ts— Controller handlersrc/repositories/EmployeeRepository.ts— Mock data repositorysrc/integrations/data-source.ts— TypeORM DataSource configurationsrc/entity/User.ts— Example User entitydocker-compose.yml— Local PostgreSQL service
- Database connection fails / timeout
- Ensure Docker container is running:
docker compose ps - Verify env vars match docker-compose credentials
- Confirm port 5432 is not blocked by another service
- Ensure Docker container is running:
- Migrations do nothing
- Ensure your entities are included in the DataSource
entitiesarray - Make sure the
src/migrationfolder exists and you pass a proper output path when generating
- Ensure your entities are included in the DataSource
- Application starts but queries fail
- The server begins listening before DB init completes. Check logs for
Database initializedto confirm connection. Add retry or health checks if needed for your environment.
- The server begins listening before DB init completes. Check logs for
ISC (see package.json).
curl http://localhost:3002/ready