Moleculer Microservices Framework
Moleculer is a fast, modern, and powerful microservices framework for Node.js, designed to build efficient, reliable, and scalable distributed systems. It provides a comprehensive set of features including a promise-based request-reply mechanism, event-driven architecture, dynamic service discovery, load balancing, and fault tolerance capabilities like Circuit Breaker and Retry. The current stable version is 0.15.0, with frequent minor and patch releases, and major updates approximately annually, often introducing significant breaking changes. Key differentiators include its pluggable architecture for transporters (e.g., NATS, Redis, Kafka), serializers (e.g., MsgPack, CBOR), caching, loggers, and metrics/tracing reporters. It emphasizes a master-less architecture, making all nodes equal, and comes with built-in parameter validation and extensive TypeScript support.
Common errors
-
Error: Missing transporter module.
cause You configured a transporter (e.g., 'NATS', 'Redis') in your `ServiceBroker` options but did not install its corresponding npm package.fixInstall the required package. For example, if using NATS, run `npm install nats` (or `yarn add nats`). -
TypeError: broker.call is not a function or broker.emit is not a function
cause Attempting to call actions or emit events on the `ServiceBroker` instance before it has been started or after it has been stopped.fixEnsure `broker.start()` has successfully resolved before making any calls or emits. Wrap your logic within the `.then()` block of `broker.start()` or ensure a running broker instance. -
Service not found
cause You are trying to call an action on a service that hasn't been created, registered, or is not available in the network.fixVerify the service name and action name are correct. Ensure the service is created with `broker.createService()` and the broker is started, allowing it to discover services across the network.
Warnings
- breaking Moleculer v0.15.0 significantly increased the minimum Node.js version requirement. It now requires Node.js >= 22.x.x.
- breaking The Moleculer communication protocol has been changed in v0.15.0 to version 5. Nodes running v0.15.x will not be able to communicate with nodes running v0.14.x or older due to protocol incompatibility.
- breaking Schema-based serializers were removed from the core in v0.15.0. If you were relying on custom schema-based serializers, they need to be reimplemented or replaced with other serialization options.
- gotcha Moleculer relies heavily on various peer dependencies for its pluggable components (transporters, loggers, serializers, metrics, tracing). Forgetting to install the specific peer dependency for a chosen component will lead to runtime errors.
- gotcha When developing with TypeScript, ensure your `tsconfig.json` targets an ECMAScript version that supports `async/await` (e.g., `es2017` or higher) and includes `esnext.asynciterable` if using streams, and that `moduleResolution` is set to `node` or `nodenext`.
Install
-
npm install moleculer -
yarn add moleculer -
pnpm add moleculer
Imports
- ServiceBroker
const { ServiceBroker } = require('moleculer');import { ServiceBroker } from 'moleculer'; - Service
import Service from 'moleculer/service';
import { Service } from 'moleculer'; - ServiceSchema
import { ServiceSchema } from 'moleculer/types';import { ServiceSchema } from 'moleculer'; - Transporters
import { NatsTransporter } from 'moleculer/transporters/nats';import { Transporters } from 'moleculer';
Quickstart
import { ServiceBroker, ServiceSchema } from 'moleculer';
// Create a ServiceBroker
const broker = new ServiceBroker({
nodeID: 'node-greeter-1',
logLevel: 'info',
transporter: 'NATS' // Or 'Redis', 'TCP', etc.
});
// Define a Greeter Service
const GreeterService: ServiceSchema = {
name: 'greeter',
settings: {
defaultName: 'World'
},
actions: {
hello: {
rest: 'GET /hello',
async handler(ctx) {
return `Hello ${ctx.params.name || this.settings.defaultName}`;
}
},
welcome: {
async handler(ctx) {
this.logger.info(`Welcoming ${ctx.params.name}...`);
return `Welcome, ${ctx.params.name}`;
}
}
},
events: {
'user.created': {
async handler(ctx) {
this.logger.info(`User created event received for ${ctx.params.username}`);
}
}
},
async started() {
this.logger.info(`Greeter service started on node ${broker.nodeID}`);
},
async stopped() {
this.logger.info(`Greeter service stopped on node ${broker.nodeID}`);
}
};
// Create a service from the schema
broker.createService(GreeterService);
// Start the broker
broker.start()
.then(async () => {
// Call an action
const res = await broker.call('greeter.hello', { name: 'Moleculer' });
console.log(res);
// Emit an event
await broker.emit('user.created', { username: 'Alice' });
// Call an action from another node if available (assuming multiple nodes)
const welcomeMsg = await broker.call('greeter.welcome', { name: 'Bob' });
console.log(welcomeMsg);
// Stop the broker after a delay or on signal
setTimeout(() => broker.stop(), 5000);
})
.catch(err => {
broker.logger.error('Error starting broker:', err);
});