Production-ready NestJS microservices monorepo β JWT auth, post management, async workers, shared ORM-agnostic database packages, Kong API gateway, and gRPC inter-service communication.
graph LR
Client(["Client"])
subgraph Gateway["API Gateway"]
Kong["Kong\n:8000"]
end
subgraph Services["Services"]
AuthSvc["auth-service\nHTTP :9001 | gRPC :50051"]
PostSvc["post-service\nHTTP :9002 | gRPC :50052"]
end
subgraph Workers["Async Workers"]
AuthWorker["auth-worker\ngRPC :50053"]
PostWorker["post-worker\ngRPC :50054"]
end
subgraph Packages["Shared DB Packages"]
AuthDB["@backendworks/auth-db\nUser Β· Role"]
PostDB["@backendworks/post-db\nPost"]
end
subgraph Infra["Infrastructure"]
PG[("PostgreSQL\n:5432")]
Redis[("Redis\n:6379")]
RMQ["RabbitMQ\n:5672"]
Mail["Mailhog\n:1025"]
end
Client --> Kong
Kong -->|"HTTP"| AuthSvc
Kong -->|"HTTP"| PostSvc
PostSvc -->|"gRPC ValidateToken"| AuthSvc
AuthSvc -->|"gRPC async jobs"| AuthWorker
PostSvc -->|"gRPC async jobs"| PostWorker
AuthSvc --> AuthDB
AuthWorker --> AuthDB
PostSvc --> PostDB
PostWorker --> PostDB
AuthDB --> PG
PostDB --> PG
AuthSvc --> Redis
PostSvc --> Redis
AuthWorker --> RMQ
PostWorker --> RMQ
AuthWorker --> Mail
| Repo | Type | HTTP | gRPC | DB Package |
|---|---|---|---|---|
| auth-service | Service | :9001 |
:50051 |
@backendworks/auth-db |
| post-service | Service | :9002 |
:50052 |
@backendworks/post-db |
| auth-worker | Worker | β | :50053 |
@backendworks/auth-db |
| post-worker | Worker | β | :50054 |
@backendworks/post-db |
| auth-db | Package | β | β | Prisma (User, Role) |
| post-db | Package | β | β | Prisma (Post) |
- gRPC-based auth in post-service β
post-servicevalidates Bearer tokens by callingauth-servicevia gRPC (ValidateToken). No Passport. Authenticated user (id,role) is injected intorequest.user. - ORM-agnostic packages β
auth-dbandpost-dbexpose repository interfaces (IUserRepository,IPostRepository). Apps never importPrismaClientdirectly. Swap the ORM by changing only the package internals. - Database migrations owned by packages β Never add a
schema.prismainside an app or worker. Runprisma migrate devfrompackages/auth-db/orpackages/post-db/. - Workers are async consumers β
auth-workerhandles email dispatch and cleanup jobs.post-workerhandles search indexing and media processing. Both communicate via gRPC and Redis queues.
git clone --recurse-submodules https://github.com/BackendWorks/nestjs-microservices.git
cd nestjs-microservices
docker-compose up --buildServices will be available at:
- Kong Gateway:
http://localhost:8000 - Auth Service:
http://localhost:9001β Swagger at/docs - Post Service:
http://localhost:9002β Swagger at/docs
Each app is developed independently from its own directory:
# Auth Service
cd auth-service && npm install && npm run dev
# Post Service
cd post-service && npm install && npm run dev
# Auth Worker
cd auth-worker && npm install && npm run dev
# Post Worker
cd post-worker && npm install && npm run devNote:
npm run proto:generatemust be run before first start or after editing.protofiles.npm run devdoes this automatically.
NODE_ENV=local
APP_PORT=9001
DATABASE_URL=postgresql://admin:master123@localhost:5432/postgres?schema=public
ACCESS_TOKEN_SECRET_KEY=your-access-secret
ACCESS_TOKEN_EXPIRED=1d
REFRESH_TOKEN_SECRET_KEY=your-refresh-secret
REFRESH_TOKEN_EXPIRED=7d
REDIS_URL=redis://localhost:6379
REDIS_KEY_PREFIX=auth:
REDIS_TTL=3600
GRPC_URL=0.0.0.0:50051NODE_ENV=local
APP_PORT=9002
DATABASE_URL=postgresql://admin:master123@localhost:5432/postgres?schema=public
ACCESS_TOKEN_SECRET_KEY=your-access-secret
REDIS_URL=redis://localhost:6379
REDIS_KEY_PREFIX=post:
REDIS_TTL=3600
GRPC_URL=0.0.0.0:50052
GRPC_AUTH_URL=0.0.0.0:50051All external traffic routes through Kong on :8000.
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/auth/login |
Public | Login, returns access + refresh tokens |
POST |
/auth/signup |
Public | Register new user |
GET |
/auth/refresh |
Bearer (refresh) | Rotate tokens |
GET |
/user/me |
Bearer | Get authenticated user profile |
GET |
/admin/user |
Admin | List users (paginated) |
PATCH |
/admin/user/:id |
Admin | Update user |
DELETE |
/admin/user/:id |
Admin | Soft-delete user |
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/post |
Public | List posts (paginated, searchable) |
POST |
/post |
Bearer | Create post |
GET |
/post/:id |
Bearer | Get post by ID |
PATCH |
/post/:id |
Bearer | Update post |
DELETE |
/post/:id |
Bearer | Soft-delete post |
GET http://localhost:9001/health
GET http://localhost:9002/health
Migrations are owned by the shared packages, not the apps.
# Auth domain
cd packages/auth-db
npm run prisma:migrate # prisma migrate dev
npm run prisma:generate # regenerate Prisma client
npm run prisma:studio # open Prisma Studio
# Post domain
cd packages/post-db
npm run prisma:migrate
npm run prisma:generate
npm run prisma:studioAll services enforce 100% branch/function/line/statement coverage.
cd auth-service && npm test
cd post-service && npm test
cd auth-worker && npm test
cd post-worker && npm testConfigured declaratively in kong/config.yml:
| Route | Limit |
|---|---|
| Auth routes | 100 req/min |
| Post routes | 200 req/min |
| Global | 300 req/min |
@backendworks/auth-db and @backendworks/post-db are published to GitHub Packages. Ensure ~/.npmrc contains:
@backendworks:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=YOUR_GITHUB_PAT