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-coursecd moleculer-coursenpm 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:
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.
Run it:
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
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:
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.
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:
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.