Production-ready TypeScript microservices with AI-powered development workflow
β¨ Claude Code + Cursor AI Ready | π³ Docker Native | π Railway Template | π Complete Auth
An AI-enhanced microservices starter that gets you from zero to production in minutes. Built for modern development with Claude Code and Cursor integration, featuring complete authentication, microservices architecture, and one-click Railway deployment.
π€ AI-First Development
- Pre-configured Claude Code context (CLAUDE.md)
- Cursor IDE integration with Sonnet-4
- AI-aware project conventions and patterns
- Intelligent code completion and suggestions
π Railway Template Ready
- One-click deployment to Railway
- Pre-configured for microservices scaling
- Environment-specific deployments (dev/staging/prod)
- Auto-detected Dockerfiles for each service
ποΈ Production Architecture
- Microservices with dedicated email & token cleanup services
- JWT authentication with refresh token rotation
- Redis-backed queues and caching
- PostgreSQL with Prisma ORM
- Comprehensive logging and monitoring
π§ Developer Experience
- TypeScript throughout with absolute imports
- Hot reload development environment
- Automated release management
- Quality gates (ESLint, Prettier, TypeScript)
- Docker containerization
- Node.js + TypeScript
- Express
- Prisma ORM + PostgreSQL
- Redis (JWT blacklist + Bull queues)
- JWT authentication (15m access + 7d refresh tokens) + scoped admin tokens (health/logs)
- Bull queue system for reliable email processing
- Microservices architecture (email-service, token-cleanup)
- Winston structured logging (env-aware)
- CORS per environment via config
- Docker containerization
- Railway-ready (dev/staging/prod)
- User registration/login with validation (email + strong password)
- JWT access tokens (15m) + refresh tokens (7d) with rotation
- Password reset and email verification flows
- Admin-only token minting for health/logs endpoints
- Role-based access control (
user,admin) - Fire-and-forget email processing via microservice
- Automated token cleanup via dedicated microservice
- Centralized error handling
- Strong logging with global metadata (version, environment, service)
- Secure CORS configuration per environment
- Queue-based architecture for async operations
src/
βββ app.ts # Express app wiring (CORS, security, parsers, routes, errors)
βββ server.ts # Server bootstrap + startup logs
βββ config/
β βββ env.ts # getEnvVar helper (no defaults; explicit envs)
β βββ index.ts # Typed config, reads env vars
βββ controllers/
β βββ authController.ts # register, login, logout, refresh, password reset, email verify
β βββ exampleController.ts
β βββ healthController.ts
βββ middleware/
β βββ errorHandler.ts # Central error middleware
β βββ tokenAuthHandler.ts # JWT verification + blacklist check
βββ routes/
β βββ index.ts # Route aggregation
β βββ v1/
β βββ authRoute.ts # /v1/auth routes
β βββ healthRoute.ts
β βββ logsRoute.ts
β βββ homeRoute.ts
βββ services/
β βββ redis/
β β βββ jwtBlacklist.ts # blacklistToken, isTokenBlacklisted
β β βββ refreshTokens.ts # refresh token management
β β βββ redisClient.ts # Redis connection
β βββ authTokenService.ts # password reset & email verification tokens
β βββ emailQueueService.ts # fire-and-forget email processing
βββ utils/
β βββ assertions/ # Validation (isValidEmail, isStrongPassword)
β βββ logger.ts # Winston logger
microservices/
βββ email-service/ # Dedicated email processing microservice
β βββ src/
β βββ Dockerfile
β βββ package.json
β βββ README.md
βββ token-cleanup/ # Automated token cleanup microservice
βββ src/
βββ Dockerfile
βββ package.json
βββ README.md
- Click the "Deploy on Railway" button above
- Connect your GitHub account
- Railway will automatically:
- Fork this repository
- Set up PostgreSQL and Redis
- Deploy all microservices
- Configure environment variables
- Your app will be live in ~3 minutes!
- Node.js 18+
- PostgreSQL database per environment (dev/staging/prod)
- Redis instance per environment (or shared with env-specific keys)
# Clone and install
git clone <your-repo-url>
cd nodejs-microservices-starter
yarn installCreate the following files in the repo root (values are examples):
# .env.development
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://user:pass@localhost:5432/myapp_dev
JWT_SECRET=dev_jwt_secret
HEALTH_SECRET=dev_health_secret
LOGS_SECRET=dev_logs_secret
REDIS_URL=redis://localhost:6379
ALLOWED_ORIGINS=http://localhost:3001# .env.staging
NODE_ENV=staging
DATABASE_URL=postgresql://...staging
JWT_SECRET=staging_jwt_secret
HEALTH_SECRET=staging_health_secret
LOGS_SECRET=staging_logs_secret
REDIS_URL=redis://...
ALLOWED_ORIGINS=https://staging-frontend.yourapp.com# .env.production
NODE_ENV=production
DATABASE_URL=postgresql://...production
JWT_SECRET=prod_jwt_secret
HEALTH_SECRET=prod_health_secret
LOGS_SECRET=prod_logs_secret
REDIS_URL=redis://...
ALLOWED_ORIGINS=https://yourapp.com,https://www.yourapp.comNotes:
- No defaults are used for critical variables; missing envs will throw at startup.
- Railway sets
PORTautomatically; you do not need to set it there.
This template is optimized for AI-assisted development:
- π CLAUDE.md: Complete project context for Claude Code sessions
- π― Conventions: AI-aware coding patterns and architecture
- π οΈ Commands: Pre-configured yarn scripts for AI suggestions
- π cursor_context.md: Mirrors CLAUDE.md for Cursor AI
- βοΈ .cursorrules: Auto-applied coding standards
- π Sync: Automatic context synchronization
π§ Smart Context Files
CLAUDE.md- Complete project context for Claude Codecursor_context.md- Mirrors context for Cursor IDE.cursorrules- Auto-applied coding standards- Synchronized documentation across all AI tools
π― AI-Optimized Patterns
# AI understands these semantic commands
yarn quality # Runs type-check + lint + format
yarn release:minor # Intelligent version bumping
yarn migrate:dev # Context-aware DB migrations
yarn dev # Hot reload with AI suggestionsπ Instant AI Onboarding
- Zero configuration needed for Claude Code or Cursor
- AI instantly understands your architecture and patterns
- Contextual suggestions based on microservices best practices
- Automated code quality and consistency
{
"dev": "dotenv -e .env.development -- ts-node-dev --respawn --transpile-only -r tsconfig-paths/register src/server.ts",
"staging": "dotenv -e .env.staging -- ts-node-dev --respawn --transpile-only -r tsconfig-paths/register src/server.ts",
"build": "tsc",
"start": "dotenv -e .env.production -- node dist/server.js",
"migrate:generate": "dotenv -e .env.development -- prisma migrate dev --create-only",
"migrate:dev": "dotenv -e .env.development -- prisma migrate deploy",
"migrate:staging": "dotenv -e .env.staging -- prisma migrate deploy",
"migrate:prod": "dotenv -e .env.production -- prisma migrate deploy"
}# Development backend on http://localhost:3000
yarn dev
# Staging-config backend locally
yarn staging
# Start all services with Docker
docker-compose upWhen you deploy via Railway template:
- PostgreSQL is auto-provisioned and connected
- Migrations run automatically during deployment
- Ready to use - no manual setup needed!
- Set up PostgreSQL locally or use a cloud provider
- Configure DATABASE_URL in your
.env.development:DATABASE_URL=postgresql://user:password@localhost:5432/myapp_dev
- Run initial migration to create tables:
yarn migrate:dev
- Generate Prisma client:
yarn prisma generate
The starter includes a minimal authentication schema:
users- User accounts with email verificationauth_tokens- Password reset & email verification tokens
Location: prisma/schema.prisma | Generated client: generated/prisma/
# Development: Apply migrations and generate client
yarn migrate:dev
# Production environments: Apply migrations only
yarn migrate:staging # For staging environment
yarn migrate:prod # For production environment
# Create new migration (when you modify schema)
yarn migrate:generate -- --name your_migration_name
# Generate Prisma client after schema changes
yarn prisma generateFor Railway Deployment:
- Database is auto-configured β
- Migrations run automatically β
- No manual setup required β
For Manual Deployment:
- Run
yarn migrate:prodafter first deployment - Run migrations after each schema change
- Generate client in build process
For Local Development:
- Run
yarn migrate:devafter cloning - This creates tables and generates the client
- Redis also required (see docker-compose.yml)
When you first clone this template:
- No existing migrations - The template starts clean
- Run
yarn migrate:dev- This will:- Create your first migration based on the schema
- Apply it to your database
- Generate the Prisma client
- Database ready - You now have
usersandauth_tokenstables
The starter schema includes everything needed for authentication!
- POST
/v1/auth/register(with email verification) - POST
/v1/auth/login - POST
/v1/auth/refresh(refresh access token) - POST
/v1/auth/logout(blacklists token, optional ?all=true) - POST
/v1/auth/forgot-password - POST
/v1/auth/reset-password - POST
/v1/auth/change-password(authenticated) - POST
/v1/auth/verify-email - POST
/v1/auth/resend-verification - GET
/v1/auth/health-token(admin only) - GET
/v1/auth/logs-token(admin only)
- Access token: 15 minutes, signed with
JWT_SECRET - Refresh token: 7 days, stored in Redis with session rotation
- Password reset tokens: 1 hour, database-backed with single use
- Email verification tokens: 24 hours, database-backed with single use
- Health/Logs tokens: 1 hour, signed separately (
HEALTH_SECRET,LOGS_SECRET). Intended for service endpoints like/v1/healthand/v1/logs
- Verifies token using the expected secret (based on route scope) and populates
req.user. - Checks Redis blacklist for access tokens (revoked on logout). If blacklisted β 401.
- Blacklists current access token in Redis with TTL matching token expiry.
- Health/Logs tokens are not blacklisted during user logout (different scope/use).
- Email:
utils/assertions/isValidEmail.ts - Password strength:
utils/assertions/isStrongPassword.ts
Configured in src/app.ts using config.allowedOrigins from ALLOWED_ORIGINS (comma-separated).
- Local dev:
http://localhost:3001(your Next.js app) - Staging/Prod: set to the corresponding frontend domain per environment
- Winston logger with environment-aware formatting:
- Development: human-readable with structured metadata appended
- Production: JSON logs suitable for aggregation
- Global metadata on every log:
version,environment,service - Startup log includes port/url; auth logs include
userId,email,ip,userAgentwhen relevant - File transport writes to
logs/server.log
Examples:
[2025-07-26T00:30:10.171Z] INFO: Server started {"version":"1.0.0","environment":"development","service":"nodejs-microservices-starter","port":"3000","url":"http://localhost:3000"}
[... ] INFO: User logged in successfully {"userId":"abc123","email":"user@example.com","role":"user","ip":"::1","userAgent":"Mozilla/5.0 ..."}
services/redis/redisClient.tsconnects on import and logs errorsservices/redis/jwtBlacklist.tsexposes:blacklistToken(token, ttl)isTokenBlacklisted(token)
This template is optimized for Railway's platform
- Create Railway service using "GitHub Repo" option
- Set environment variables per service (see Environment Files)
- Railway provides
PORTautomatically
For each microservice (email-service, token-cleanup):
- Create "Empty Service" in Railway dashboard
- Connect to GitHub after service is created
- Set the root directory to point to microservice folder:
microservices/email-servicemicroservices/token-cleanup
- Railway auto-detects the Dockerfile in that directory
- Configure environment variables in service settings
- Deploy happens automatically after setup
After promoting code, run:
# In staging service shell
yarn migrate:staging
# In production service shell
yarn migrate:prod- Use Semantic Versioning (MAJOR.MINOR.PATCH)
- Recommended PR naming:
- Dev β Staging:
Staging v1.0.0 - Staging β Main:
Release v1.0.0
- Dev β Staging:
- Create git tags for production releases:
v1.0.0,v1.1.0, etc. (via GitHub/GitLab Releases or CLI)
- 401 "Invalid token": Check
Authorization: Bearer <token>and token not blacklisted - 400 on logout: ensure Redis is reachable and connected
ClientClosedError: The client is closed: Redis client wasnβt connected β the app now connects on import- CORS blocked: verify
ALLOWED_ORIGINSis set correctly for the environment - Missing DB column (e.g.,
role): runnpm run migrate:<env>against that environment Environment variable ... is missing.: set it in the env file or Railway variables
- Queue-based email processing with Bull and Redis
- Support for password reset, email verification, and notification emails
- Template system with Handlebars
- Multiple email provider support (Nodemailer, SendGrid, AWS SES)
- Health monitoring and retry logic
- Automated cleanup of expired authentication tokens
- Configurable cron scheduling (default: every 6 hours)
- Comprehensive logging and statistics
- Independent scaling and monitoring
- Rate limiting rules per route group
- Observability/metrics integration
- Test suite (unit/integration)
- Additional microservices (notifications, analytics)
ISC