Phase 1 - Foundation | Post 2 | Installation and Your First Working Moleculer Service

Post 2 of 15 | Phase 1: Foundation


Installation and Your First Working Moleculer Service

In the previous post you learned what Moleculer is and why it exists. In this post you will install everything, set up a proper project structure, and build your first working service. Every line of code will be explained.


What You Need Installed on Your Machine

Before writing any Moleculer code, confirm you have the following:

  • Node.js version 18 or above. Moleculer 0.15 requires minimum Node 18.
  • npm, which comes bundled with Node.js.
  • A code editor. VS Code is recommended.

Check your Node version:


    node -v

If it shows below v18, go to nodejs.org, download the LTS version, and install it.


Setting Up the Project

You have two ways to create a Moleculer project.

Way 1: Moleculer CLI (recommended)

The CLI scaffolds a complete project with proper folder structure, config file, and example services automatically.

Way 2: Manual setup

Create a folder, run npm init, install moleculer, write everything yourself.

We will start with the CLI because it reflects real-world usage. Then we will manually go through each generated file so you understand exactly what everything does.


Manual Setup — Step by Step

Step 1: Create a project folder


    mkdir moleculer-course
    cd moleculer-course
    npm init -y

Step 2: Install Moleculer


    npm install moleculer

That is it. No other dependency is needed to run your first service.

Step 3: Check your folder structure

After these steps your folder should look like this:


    moleculer-course/
        node_modules/
        package.json
        package-lock.json

Step 4: Create your first file

Create a file called index.js in the root of the project.


Writing Your First Service

Open index.js and write the following code. Read each comment carefully.


    // Step 1: Import ServiceBroker from the moleculer package
    const { ServiceBroker } = require("moleculer");

    // Step 2: Create a broker instance
    // The broker is the central manager of your entire Moleculer app
    // Think of it as the "boss" who knows about all services and routes calls
    const broker = new ServiceBroker();

    // Step 3: Create a service
    // A service is a module that does one specific job
    // This one is called "greeter" and it handles greeting-related tasks
    broker.createService({
        name: "greeter",   // This is the service name. Used when calling its actions.

        actions: {
            // An action is a function that can be called by other services or externally
            // This action is called "hello"
            // Full action name becomes: "greeter.hello"
            hello(ctx) {
                // ctx is the Context object
                // ctx.params contains whatever data was passed when calling this action
                const name = ctx.params.name;
                return `Hello, ${name}! Welcome to Moleculer.`;
            },

            // A second action on the same service
            // Full action name: "greeter.welcome"
            welcome(ctx) {
                const { firstName, lastName } = ctx.params;
                return `Welcome, ${firstName} ${lastName}!`;
            }
        }
    });

    // Step 4: Start the broker
    // broker.start() returns a Promise
    // The .then() runs after broker has fully started and all services are ready
    broker.start()
        .then(() => {
            // Step 5: Call an action
            // broker.call("serviceName.actionName", { ...params })
            // This returns a Promise that resolves with the action's return value
            return broker.call("greeter.hello", { name: "Rahul" });
        })
        .then(result => {
            console.log(result);
            // Output: Hello, Rahul! Welcome to Moleculer.
        });

Run it:


    node index.js

You should see output like this in your terminal:

[2025-05-12T10:00:00.000Z] INFO  broker/BROKER: Moleculer v0.15.0 is starting...

[2025-05-12T10:00:00.000Z] INFO  broker/BROKER: Node ID: my-pc-1234

[2025-05-12T10:00:00.000Z] INFO  broker/BROKER: Service 'greeter' registered.

Hello, Rahul! Welcome to Moleculer.

Your first Moleculer service is working.


Breaking Down What Just Happened

Let us go through each part carefully.

ServiceBroker


    const broker = new ServiceBroker();

This creates the central brain of your Moleculer app. When you call this with no arguments, it uses default settings — console logging, no transporter (everything runs in the same process), and auto-generated node ID.

createService

    
    broker.createService({ name: "greeter", actions: { ... } });

This registers a service with the broker. The broker now knows this service exists and can route calls to it. The name field is mandatory. Every service must have a unique name.

Actions and the ctx object


    hello(ctx) {
        return ctx.params.name;
    }

Every action receives one argument — the Context object, always named ctx by convention. The ctx.params object contains the data you passed when calling the action. You return a value from the action and the caller receives it as the result.

broker.call


    broker.call("greeter.hello", { name: "Rahul" })

This is how you call an action. First argument is the full action name in the format "serviceName.actionName". Second argument is the params object, which becomes ctx.params inside the action. It always returns a Promise.


Calling Multiple Actions

Update your index.js to call both actions:


    const { ServiceBroker } = require("moleculer");

    const broker = new ServiceBroker();

    broker.createService({
        name: "greeter",
        actions: {
            hello(ctx) {
                return `Hello, ${ctx.params.name}! Welcome to Moleculer.`;
            },
            welcome(ctx) {
                const { firstName, lastName } = ctx.params;
                return `Welcome, ${firstName} ${lastName}!`;
            }
        }
    });

    broker.start()
        .then(async () => {
            // Using async/await instead of chaining .then()
            // Both approaches work. async/await is cleaner for multiple calls.

            const result1 = await broker.call("greeter.hello", { name: "Rahul" });
            console.log(result1);

            const result2 = await broker.call("greeter.welcome", {
                firstName: "Rahul",
                lastName: "Sharma"
            });
            console.log(result2);
        });

Output:
Hello, Rahul! Welcome to Moleculer. Welcome, Rahul Sharma!

Using Multiple Services

In a real microservices project, you will have many services. Here is how two services look in the same broker, and how one service calls another.


    const { ServiceBroker } = require("moleculer");

    const broker = new ServiceBroker();

    // Service 1: math service
    broker.createService({
        name: "math",
        actions: {
            add(ctx) {
                return ctx.params.a + ctx.params.b;
            },
            multiply(ctx) {
                return ctx.params.a * ctx.params.b;
            }
        }
    });

    // Service 2: calculator service
    // This service calls the math service internally
    broker.createService({
        name: "calculator",
        actions: {
            // This action calls another service's action using ctx.call()
            // ctx.call() is the same as broker.call() but used from inside a service
            async compute(ctx) {
                const sum = await ctx.call("math.add", { a: ctx.params.x, b: ctx.params.y });
                const product = await ctx.call("math.multiply", { a: ctx.params.x, b: ctx.params.y });
                return {
                    sum,
                    product
                };
            }
        }
    });

    broker.start()
        .then(async () => {
            const result = await broker.call("calculator.compute", { x: 4, y: 5 });
            console.log(result);
            // Output: { sum: 9, product: 20 }
        });

Two important things to notice here.

First, inside a service action, you use ctx.call() to call other actions, not broker.call(). Both work, but ctx.call() is the correct way because it carries the request context forward, which matters for tracing and metadata later in the course.

Second, services in the same broker can call each other freely. The broker routes the call automatically. You do not need to know where the other service is running.


Installing the Moleculer CLI

Run this once globally on your machine:


    npm install -g moleculer-cli

Verify it installed correctly:


    moleculer --version


Creating Your Project

Navigate to wherever you keep your projects and run:


    moleculer init project my-project

The CLI will ask you a series of questions. Answer exactly as shown below:
Add HTTP API Gateway (moleculer-web) service? Yes
Add GraphQL Gateway? No
Add Socket.Io Gateway? No
Would you like to communicate with other nodes? No
Would you like to use cache? No
Add DB sample service? No
Add Moleculer Channels middleware? No
Add Moleculer Workflows middleware? No
Would you like to enable metrics? No
Would you like to enable tracing? No
Add Docker & Kubernetes sample files? No
Use ESLint to lint your code? No
Would you like to run npm install? Yes

The most important one is "Add DB sample service? No". If you select Yes here, it installs sqlite3 which is a native module that requires Visual Studio Build Tools to compile on Windows. Avoiding it keeps the setup simple for now. We will add our own database integration later in the course using MongoDB.

After npm install completes you should see no errors. Your terminal should end cleanly without any npm error lines.


Understanding the Generated Folder Structure

Open the my-project folder in VS Code. You will see this structure:

my-project/
  services/
    api.service.js
    greeter.service.js
  moleculer.config.js
  package.json
  package-lock.json
  node_modules/

Here is what each file does.

services/greeter.service.js

This is an example service. It has two actions called hello and welcome. This is where you will learn the structure of a real service file.

services/api.service.js

This is the API Gateway service. It exposes your internal Moleculer services over HTTP so the outside world can reach them via a browser or Postman. Think of it as the front door of your application.

moleculer.config.js

This is the central configuration file for your ServiceBroker. Logger settings, transporter settings, caching settings — all go here. We will go through this file in detail in Post 3.


Running the Project

Go into the project folder:

cd my-project

Start the project:

npm run dev

You should see output like this in your terminal:

[INFO]  broker/BROKER: Moleculer v0.15.0 is starting...
[INFO]  broker/BROKER: Node ID: my-pc-1234
[INFO]  broker/BROKER: Service 'greeter' registered.
[INFO]  broker/BROKER: Service 'api' registered.
[INFO]  broker/BROKER: ServiceBroker started successfully.
[INFO]  api/API-GW: API Gateway listening on http://0.0.0.0:3000

Your application is now running. The API Gateway is listening on port 3000.

Open your browser and go to:

http://localhost:3000/api/greeter/welcome?name=Rahul

You should see:

"Welcome, Rahul"

That response came from the greeter service, through the API Gateway, over HTTP. You just called a Moleculer action from a browser.


Understanding the Greeter Service File

Open services/greeter.service.js. It looks like this:


    "use strict";

    /**
     * @typedef {import('moleculer').ServiceSchema} ServiceSchema Moleculer's Service Schema
     * @typedef {import('moleculer').Context} Context Moleculer's Context
     */

    /** @type {ServiceSchema} */
    module.exports = {
        name: "greeter",

        /**
         * Settings. More info: https://moleculer.services/docs/0.15/services.html#Settings
         */
        settings: {},

        /**
         * Dependencies. More info: https://moleculer.services/docs/0.15/services.html#Dependencies
         */
        dependencies: [],

        /**
         * Actions. More info: https://moleculer.services/docs/0.15/actions.html
         */
        actions: {
            /**
             * Say a 'Hello' action.
             *
             * @returns
             */
            hello: {
                rest: {
                    method: "GET",
                    path: "/hello"
                },

                async handler() {
                    return "Hello Moleculer";
                }
            },

            /**
             * Welcome, a username
             *
             * @param {String} name - User name
             */
            welcome: {
                rest: "/welcome",
                params: {
                    name: "string"
                },

                /** @param {import('moleculer').Context<{name: String}>} ctx */
                async handler(ctx) {
                    return `Welcome, ${ctx.params.name}`;
                }
            }
        },

        /**
         * Events. More info: https://moleculer.services/docs/0.15/events.html
         */
        events: {},

        /**
         * Methods. More info: https://moleculer.services/docs/0.15/services.html#Methods
         */
        methods: {},

        /**
         * Service created lifecycle event handler
         * More info: https://moleculer.services/docs/0.15/lifecycle.html#created-event-handler
         * @this {import('moleculer').Service}
         */
        created() { },

        /**
         * Service started lifecycle event handler
         * More info: https://moleculer.services/docs/0.15/lifecycle.html#started-event-handler
         * @this {import('moleculer').Service}
         */
        async started() { },

        /**
         * Service stopped lifecycle event handler
         * More info: https://moleculer.services/docs/0.15/lifecycle.html#stopped-event-handler
         * @this {import('moleculer').Service}
         */
        async stopped() { }
    };


Let us go through each part.

module.exports

A Moleculer service file exports a plain JavaScript object. No class, no constructor, just an object. The broker reads this object and registers it as a service.

name

Every service must have a name. This is how other services and the broker identify it. The name greeter means its actions are called as greeter.hello and greeter.welcome.

settings

An optional object for service-level configuration. For example, default page size for a list action, or a base URL. We will use this in later posts.

actions

This is where all the callable functions live. Each key inside actions is one action.

rest

This tells the API Gateway how to expose this action over HTTP. method is the HTTP method, path is the URL path. So greeter.hello becomes GET /api/greeter/hello.

params

An optional validation schema. If you define params, Moleculer automatically validates incoming data before the handler runs. In the welcome action, name must be a string. If it is missing or wrong type, Moleculer throws a validation error automatically. No manual validation code needed.

handler

This is the actual function that runs when the action is called. It receives ctx which is the Context object. ctx.params contains the data passed to the action.


Writing Your First Service From Scratch

Now that you understand the structure, create a new file inside the services folder called math.service.js.


    "use strict";

    module.exports = {
        name: "math",

        actions: {
            add: {
                // Define what params this action expects
                params: {
                    a: "number",
                    b: "number"
                },
                handler(ctx) {
                    return ctx.params.a + ctx.params.b;
                }
            },

            subtract: {
                params: {
                    a: "number",
                    b: "number"
                },
                handler(ctx) {
                    return ctx.params.a - ctx.params.b;
                }
            }
        }
    };

Save the file. Because you are running npm run dev, Moleculer watches for file changes and reloads automatically. You do not need to restart the server.

You will see this in your terminal:

[INFO]  broker/BROKER: Service 'math' registered.

Now test it in your browser. But wait — you did not add a rest property to these actions. That means the API Gateway does not know how to expose them over HTTP yet.

There are two ways to call them now.

Way 1: Add rest to the actions

Update add action like this:


    add: {
        rest: {
            method: "GET",
            path: "/add"
        },
        params: {
            a: "number",
            b: "number"
        },
        handler(ctx) {
            return ctx.params.a + ctx.params.b;
        }
    },

Then visit:

http://localhost:3000/api/math/add?a=5&b=3

Response:

8

Way 2: Use the REPL console

Moleculer has a built-in interactive console called REPL. Stop the server with Ctrl+C and start it in REPL mode:

npm run repl

Now type this in the console:

call math.add {"a": 5, "b": 3}

Response:

>> 8

The REPL is extremely useful for testing actions quickly without needing HTTP or Postman. We will use it throughout the course.


How the Project Starts — Understanding package.json Scripts

Open package.json and look at the scripts section:

"scripts": {
    "dev": "nodemon services/**/*.service.js moleculer.config.js",
    "start": "moleculer-runner services",
    "repl": "moleculer-runner --repl services"
}

npm run dev uses nodemon to watch all service files and the config file. Any time you save a change, it restarts automatically. Use this during development.

npm start uses moleculer-runner which is Moleculer's own process manager. It reads moleculer.config.js and loads all service files from the services folder. Use this in production.

npm run repl starts the application with an interactive console attached. Use this for quick testing.


One Important Thing About Query Params and Numbers

When you call an action via HTTP GET with query params like ?a=5&b=3, the values arrive as strings, not numbers. So "5" + "3" would give you "53" instead of 8.

Moleculer's built-in param validation handles this automatically. When you declare params as number type, Moleculer coerces the string to a number before passing it to the handler. This is why defining params is important, not just for validation but also for type coercion.


Current Folder Structure

After adding the math service, your project looks like this:

my-project/
  services/
    api.service.js
    greeter.service.js
    math.service.js       <-- you created this
  moleculer.config.js
  package.json

This is the pattern you will follow throughout the course. One file per service, all inside the services folder. The broker automatically picks up any file matching *.service.js.


Summary

  • Use moleculer init project to scaffold a new project.
  • Always answer No to "Add DB sample service" on Windows to avoid the sqlite3 native compilation error.
  • A service file exports a plain object with name and actions.
  • Each action has an optional params schema, an optional rest definition, and a required handler function.
  • ctx.params holds the incoming data inside a handler.
  • The rest property on an action tells the API Gateway how to expose it over HTTP.
  • npm run dev for development with auto-reload.
  • npm run repl for quick action testing via the console.
  • Param type declarations handle both validation and type coercion automatically.

Up Next

Post 3 goes deep into the ServiceBroker — its configuration options, lifecycle hooks, logging settings, and how to read and customize moleculer.config.js. This is the foundation that everything else sits on.


Course Progress: 2 of 15 posts complete.

Phase 1 - Foundation | Post 1 | What is microservices and why Moleculer

Post 1 of 15 | Phase 1: Foundation


What is a Monolith and Why Does It Become a Problem?

You have built MERN or MEAN applications. In those apps, one Express server handles everything — user registration, login, products, orders, payments, emails. This is called a monolith. One big codebase, one process, one deployment.

This works fine when your app is small. The problem starts when your app grows.

Imagine one person in a restaurant doing every job — taking orders, cooking food, handling billing, washing dishes. Five customers? Fine. Five hundred customers? Everything slows down and breaks.

Your Express monolith has the same problem at scale. If one part of the code crashes or slows down, it affects the entire application.


What is Microservices?

Microservices means splitting that one big server into many small, independent services. Each service does one job only.

Using the restaurant example:

  • The waiter only takes orders
  • The chef only cooks
  • The cashier only handles payment
  • Each person works independently

If the cashier is sick, the chef still cooks. No single point of failure.

In code terms, instead of one Express app doing everything, you have:

  • user-service, handles only user registration and login
  • order-service, handles only orders
  • payment-service, handles only payments
  • email-service, handles only sending emails

Each service runs as a separate Node.js process. They communicate with each other over a network.


What is Moleculer?

Moleculer is a framework for Node.js that makes building microservices simple and structured.

Think of Moleculer as the walkie-talkie system in that restaurant. Without it, every service has to manually find and call other services using HTTP, handle failures, retry logic, load balancing — all from scratch. Moleculer takes care of all of that for you.

The latest stable version is 0.15.0. You install it with a single command.


    npm install moleculer


Why Not Just Use Express with HTTP Calls Between Services?

You could. But you would have to manually build:

  • Service discovery (how does service A find service B's address?)
  • Load balancing (if service B has 3 instances, which one to call?)
  • Retry logic (what if service B is temporarily down?)
  • Caching
  • Tracing and logging across services

Moleculer gives you all of this out of the box. You focus on business logic.


Five Core Terms You Must Know

Everything in Moleculer is built around these five concepts. Learn these first and the rest of the course will make sense.

ServiceBroker The central manager of your Moleculer application. It starts all services, manages communication between them, and handles discovery. You create one broker per Node.js process.

Service A single unit responsible for one domain. For example, a user-service or an order-service. A service has a name and contains actions and/or events.

Action A callable function inside a service. Similar to a REST endpoint, but internal. For example, user.create or order.list. Other services call actions to get a result back.

Event A broadcast message. One service emits an event, and any other service that is interested can listen and react. Unlike actions, events do not return a response. Think of it like a group notification.

Transporter The communication layer used when services run on different machines. Examples are NATS, Redis, and Kafka. For local development with everything on one machine, no transporter is needed.


What Moleculer Code Looks Like

Do not worry about understanding every detail here. Just read it and get a feel for the structure.


    const { ServiceBroker } = require("moleculer");

    // Create the broker (the manager)
    const broker = new ServiceBroker();

    // Create a service
    broker.createService({
        name: "math",
        actions: {
            add(ctx) {
                return ctx.params.a + ctx.params.b;
            }
        }
    });

    // Start the broker and call the action
    broker.start()
        .then(() => broker.call("math.add", { a: 5, b: 3 }))
        .then(result => console.log("Result:", result));
    // Output: Result: 8

Notice there is no req, no res, no route definition. The action is just a function that receives a context object and returns a value. Moleculer handles how it gets called.


Comparing Express vs Moleculer

Express approach in a monolith:


    app.get("/math/add", (req, res) => {
        const result = Number(req.query.a) + Number(req.query.b);
        res.json({ result });
    });

Moleculer approach as a service:


    broker.createService({
        name: "math",
        actions: {
            add(ctx) {
                return ctx.params.a + ctx.params.b;
            }
        }
    });

The Moleculer action has zero knowledge of HTTP. It is pure business logic. You expose it over HTTP later using the API Gateway module, which is covered in Phase 6 of this course.


What You Will Build by the End of This Course

A mini e-commerce backend with the following services:

  • API Gateway, the only service exposed to the internet via HTTP
  • user-service, handles registration, login, profile
  • order-service, handles creating and listing orders
  • payment-service, handles payment processing

All services communicate through Moleculer internally. MongoDB is used for data storage.


Full Course Roadmap

Phase 1 - Foundation Post 1: What is microservices and why Moleculer (this post) Post 2: Installation and your first working service

Phase 2 - Core Concepts Post 3: ServiceBroker in depth Post 4: Services and Actions Post 5: Events

Phase 3 - Communication Post 6: The Context object Post 7: Transporters and multi-node setup

Phase 4 - Fault Tolerance Post 8: Circuit Breaker, Retry, Timeout, Bulkhead

Phase 5 - Caching Post 9: Built-in caching with Memory and Redis

Phase 6 - API Gateway Post 10: Exposing services over HTTP with moleculer-web Post 11: REST API design with Moleculer

Phase 7 - Database Post 12: moleculer-db with MongoDB and Mongoose

Phase 8 - Observability Post 13: Logging, Metrics, and Tracing

Phase 9 - Deployment Post 14: Docker and Docker Compose Post 15: Final project — complete e-commerce backend


Summary

  • Monolith means one server doing everything. It becomes a bottleneck at scale.
  • Microservices means splitting responsibilities into small independent services.
  • Moleculer is the framework that handles communication, discovery, and fault tolerance between those services.
  • Five terms to remember: ServiceBroker, Service, Action, Event, Transporter.
  • You will build a real e-commerce backend by the end of this course.

Up Next

Post 2 covers installation, project setup, and building your first real Moleculer service with full explanation of every line.

Phase 4 - Fault Tolerance | Post 8 | Fault Tolerance — Keeping Your App Alive When Things Break

Post 8 of 15 | Phase 4: Fault Tolerance Fault Tolerance — Keeping Your App Alive When Things Break In every post so far we have assumed that...