Custom Medusa.js Service Development

Custom Medusa.js Service Development

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1284
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1240
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    982
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1031
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1104
  • image_website-_0.webp
    Website development for Red Pear
    553

Custom Medusa.js Service Development

Imagine your Medusa store processing 1000 orders per day. The first complex task: a loyalty program with points accrual for purchases and redemption for discounts. No ready-made module exists for such logic. Implementing it in API routes leads to spaghetti code and N+1 queries that slow down the response to 2 seconds. Custom services in Medusa are TypeScript classes that live in the IoC container and can do everything: from CRUD to integration with external services. We have accumulated sufficient experience in designing services for Medusa and are ready to share proven solutions. Below is an analysis using the loyalty module as an example.

Problems a Custom Service Solves

Placing business logic directly in controllers leads to N+1 queries, lack of reusability, and difficulties with unit testing. A custom service encapsulates everything: database operations, API calls, calculations. You get a module that can be called from workflows, subscribers, or the admin panel. This reduces maintenance time by 2–3 times compared to the "monolithic" approach. We guarantee the service will be designed with typical failure and retry scenarios in mind. According to Medusa documentation, custom services are the recommended way to organize complex logic.

How a Custom Service Eliminates N+1 Problem

N+1 queries are a common issue when working with related entities. Instead of making one query with JOIN, the controller executes a loop of N queries. A custom service solves this through repositories and data aggregation. For example, a loyalty service can get the sum of points for all customers in one SQL query, not one by one. This reduces response time by 60% and database load.

How We Do It (Technical Proof)

Below is a full example of a loyalty service, including module registration and usage in a Workflow.

// src/modules/loyalty/service.ts import { MedusaContainer, Logger } from '@medusajs/framework/types'; type LoyaltyPoint = { customerId: string; points: number; reason: string; orderId?: string; }; export default class LoyaltyService { protected logger: Logger; private db: any; // MikroORM or raw query constructor({ logger }: { logger: Logger }) { this.logger = logger; } async getCustomerPoints(customerId: string): Promise<number> { const result = await this.db.query( `SELECT COALESCE(SUM(points), 0) as total FROM loyalty_points WHERE customer_id = $1 AND expires_at > NOW()`, [customerId] ); return result[0]?.total ?? 0; } async addPoints(data: LoyaltyPoint): Promise<void> { this.logger.info(`Adding ${data.points} points to customer ${data.customerId}`); await this.db.query( `INSERT INTO loyalty_points (customer_id, points, reason, order_id, created_at, expires_at) VALUES ($1, $2, $3, $4, NOW(), NOW() + INTERVAL '1 year')`, [data.customerId, data.points, data.reason, data.orderId ?? null] ); } } // src/modules/loyalty/index.ts import { Module } from '@medusajs/framework/utils'; import LoyaltyService from './service'; export const LOYALTY_MODULE = 'loyaltyModuleService'; export default Module(LOYALTY_MODULE, { service: LoyaltyService }); // medusa-config.ts defineConfig({ modules: [{ resolve: './src/modules/loyalty' }] }); 

Now we use the service in a workflow (step to add points after an order):

import { createStep, StepResponse } from '@medusajs/framework/workflows-sdk'; const addLoyaltyPointsStep = createStep( 'add-loyalty-points', async (input: { orderId: string; customerId: string; orderTotal: number }, ctx) => { const service: LoyaltyService = ctx.container.resolve(LOYALTY_MODULE); const pointsToAdd = Math.floor(input.orderTotal / 100); await service.addPoints({ customerId: input.customerId, points: pointsToAdd, reason: 'order_completed', orderId: input.orderId, }); return new StepResponse({ pointsAdded: pointsToAdd }, { customerId: input.customerId, pointsToAdd }); }, async ({ customerId, pointsToAdd }, ctx) => { const service: LoyaltyService = ctx.container.resolve(LOYALTY_MODULE); await service.addPoints({ customerId, points: -pointsToAdd, reason: 'rollback' }); } ); 

Type Comparison

Type Purpose When to Use
Module Service CRUD for module entity Entity with standard operations (e.g., products, carts)
Custom Service Arbitrary business logic Specific logic needed (loyalty, ERP sync)
Workflow Step Workflow step Reusable operation across multiple scenarios
Checklist for custom service development
  • Define dependencies (logger, database, API)
  • Implement the service interface
  • Register the module in index.ts and medusa-config.ts
  • Write unit tests for critical logic
  • Add JSDoc with method descriptions
  • Test integration with Workflow and API routes

Process and Estimation

Process: Requirement analysis → Service design and dependencies → Implementation → Testing → Deployment. Takes from 1 day for simple solutions to 3 weeks for complex ones. Cost is calculated individually based on complexity. Project budget is discussed at the start. Order development and get stable logic without extra costs.

Time Estimates

Service Type Approximate Time
Simple (1–2 operations, one data source) 1–2 days
With external API integration and retry logic 3–5 days
Complex (loyalty logic, B2B pricing, custom inventory) 1–3 weeks

What's Included in Custom Service Development

We provide a complete package:

  • Architecture and service design
  • TypeScript implementation following Medusa best practices
  • Testing (unit + integration)
  • Documentation (README, JSDoc, call examples)
  • Assistance with deployment and CI setup
  • Training your team on working with the service

Contact us — we will evaluate your project and propose the optimal solution. This is an investment in the stability and growth of your e-commerce.

How a Custom Service Solves the Transactionality Problem

In addition to N+1, atomicity of operations is important. Medusa has a built-in TransactionService that allows combining multiple steps into one transaction. A custom service uses it to guarantee data integrity: for example, accruing points and applying a discount are performed in a single transaction. This eliminates desynchronization and simplifies debugging.