Building the Engine: A Deep Dive into Froodly's Custom Medusa.js Backend

Naman Kataria
Naman Kataria
September 17, 2025
Case StudyE-commerceHeadless Commerce
A technical deep dive into the custom Medusa.js backend built for Froodly. Learn how we engineered bespoke modules for GTA address validation, automated PDF invoice generation, and deployed a production-grade, multi-process architecture on Railway.
Building the Engine: A Deep Dive into Froodly's Custom Medusa.js Backend

In the first part of our series, we laid out the architectural blueprint for Froodly, a D2C grocery delivery platform built on a modern, headless foundation. With a clear strategy in place, our next task was to engineer the core of the entire operation: the backend commerce engine. This wasn't just about setting up a product database; it was about building a robust, scalable, and highly customized system that could handle the unique complexities of Froodly's business model.

A headless storefront is only as powerful as the engine driving it. For Froodly, that engine needed to do more than just manage carts and orders. It had to validate delivery zones in real-time, generate legal documents automatically, and provide live notifications to the operations team. This is the story of how we used Medusa.js as our foundation and extended it to create a truly bespoke commerce backend.

Why Medusa.js was the Perfect Foundation

We chose Medusa.js for one primary reason: extensibility. While it provides all the essential e-commerce features out of the box—products, customers, order management, promotions—its true power lies in its modular, API-first design. Medusa doesn't just allow you to customize; it expects you to. Its architecture, built on services, subscribers, and modules, gave us the hooks we needed to inject Froodly's specific business logic directly into the core system.

By using Medusa, we avoided reinventing the wheel on core commerce functionality and could instead focus our engineering efforts on the features that made Froodly unique.

The "GTA or Bust" Challenge: Engineering Custom Address Validation

Froodly's promise is "Grown here. Sold here. Delivered here." That last part is critical. Their service is exclusively for the Greater Toronto Area. We couldn't allow a customer from another province to place an order, only to be disappointed later. This validation needed to be instant, reliable, and woven into the fabric of the user experience.

To solve this, we built a custom Medusa Service. In Medusa's architecture, a service is an isolated piece of business logic that can be accessed from anywhere in the backend. Our address-validation.ts service contained a single, crucial responsibility: to determine if a given Canadian postal code belongs to the GTA.

The service maintains a comprehensive and up-to-date list of all valid GTA postal code prefixes (the first three characters, known as the Forward Sortation Area or FSA). When a user enters their postal code during checkout or while creating an address, the frontend sends a request to a custom API endpoint we created. This endpoint calls our address-validation service, which normalizes the input, extracts the FSA, and checks it against the master list. It returns a simple boolean: true if it's a match, false if it's not.

This server-side validation is authoritative. Even if a user were to bypass the client-side checks, the backend would prevent an order from being created for an invalid address. By encapsulating this critical business rule in a dedicated Medusa service, we made it reusable, testable, and centrally managed.

Beyond the Sale: Automated Invoices and Packing Slips

For a delivery business, the work has only just begun once an order is placed. The fulfillment team needs clear, accurate documentation to pick, pack, and ship orders correctly. Manually creating invoices and packing slips would be a logistical nightmare and a bottleneck to growth.

To automate this, we built a custom Documents Module for Medusa. This module leverages Medusa's event-driven architecture. We created a subscriber that listens for the order.placed event. As soon as an order is successfully confirmed, this subscriber triggers our Documents Module.

The module, using libraries like PDFKit, dynamically generates two documents:

  1. A Customer Invoice: A professionally branded PDF containing the customer's details, line items, pricing, taxes, and order total.
  2. An Internal Packing Slip: A streamlined document for the warehouse team, showing the items, quantities, and delivery information, omitting sensitive pricing details.

These generated PDFs are then stored and can be attached to transactional emails or accessed directly from the Medusa Admin dashboard. This custom module transformed a manual, error-prone operational task into a fully automated, reliable workflow.

The Unseen Hero: The Background Worker and Production-Grade Deployment

One of the hallmarks of a professional, scalable web application is the separation of concerns. A common mistake is to run everything—API requests, background jobs, admin tasks—in a single process. This is risky. A long-running task, like generating a large report or processing a batch of emails, could block the main thread and slow down or even crash the customer-facing API.

To avoid this, we followed production best practices by splitting Froodly's backend into three distinct processes, orchestrated on Railway using a Procfile:

  1. The web Process: This is the main Medusa server. Its sole responsibility is to handle incoming API requests from the storefront as quickly as possible.
  2. The worker Process: This is the background workhorse. It runs medusa-worker and subscribes to the Redis queue. Any long-running or non-time-sensitive task—like sending emails, processing webhooks, or generating documents—is offloaded to this worker. This ensures the web process is always free and responsive.
  3. The admin Process: This process serves the Medusa Admin dashboard, isolating it from the customer-facing API.

This multi-process architecture, hosted on Railway, ensures that Froodly is not only fast but also resilient. A spike in background jobs won't impact a customer's ability to check out, which is critical for a high-volume e-commerce platform.

The Froodly engine, powered by Medusa.js, is more than just a collection of APIs. It's a custom-built system of interconnected services and modules that enforces business rules, automates operations, and is architected for high performance.

But an engine is useless without a beautiful, functional car built around it. In the next part of our series, we'll shift our focus to the frontend, exploring how we designed and built the "Harvest Harmony" storefront using Next.js, navigated the challenges of a rapidly evolving React ecosystem, and crafted a user experience that is as delightful as it is functional.

About the Author

Naman Kataria

Naman Kataria

I’m Naman Kataria, a passionate developer, designer, and founder of my own development and creative + automation studio.

With over 2 years of hands-on experience, I specialize in building fast, scalable, and conversion-focused digital experiences—ranging from custom-coded websites to AI-powered automations.

I’ve worked with small businesses, creators, and emerging brands to help them stand out online through modern design, clean code, Ecommerce solutions and strategic automation. My approach blends both creativity and functionality, ensuring that every website I deliver performs just as good as it looks.

Whether it’s a personal brand site, a product landing page, or a full-featured eCommerce store, I build systems that work—built on performance-first frameworks like Next.js, styled with Tailwind CSS, and integrated with AI tools and platforms like Zapier, Make.com, and more.

Share:

Read more insights

Loading blog posts...

Ready to Implement These Strategies?

Our team can help you apply these insights to drive real results. Contact us to discuss your project requirements.