Rorix Technologies Logo
WMS Engineering Guide

Last reviewed . Architecture recommendations rechecked against the systems we currently run.

Scalable WMS Architecture: A 2026 Engineering Guide

A scalable warehouse management system is one that absorbs more warehouses, more tenants, and more SKUs without a rewrite. This guide walks through the architecture decisions that get you there, from the database under the inventory ledger to the deployment pattern that ships updates while the floor keeps moving, grounded in systems we have shipped rather than theory.

Since 2018 the same engineers have been the core engineering team behind Lorecs' supply-chain platform, a relationship that predates Rorix itself and has continued under it: two interconnected systems spanning inventory, vendor management, and warehouse and logistics operations, running multi-region, multi-currency workflows and migrating .NET Core 2.1 to .NET 9 without disrupting live operations. The decisions below are the ones that work at that scale.

What does scalable actually mean for a WMS?

Scalability for a WMS is three concrete things at once: many warehouses, many tenants, and high SKU volume, all without a rewrite when any one of them grows.

The word scalable gets used loosely, so it helps to make it specific. For a warehouse management system it means three distinct demands that arrive on different timelines. The first is multi-warehouse: the day a second, third, or tenth site comes online, the data model has to keep each location's stock, orders, and movements cleanly separated while still rolling up to a network-wide view. The reliable approach is to partition by site from the start, so a query for one facility never drags the whole dataset, and so a busy site cannot starve a quiet one.

The second is multi-tenancy, which matters most for 3PLs and platforms serving many clients from one system. The choice is between row-level isolation, where a tenant identifier scopes every query, and schema-level isolation, where each tenant gets its own schema. Row-level is simpler to operate and is the common default; schema-level offers stronger separation at higher operational cost. The wrong move is to defer the decision, because retrofitting tenant isolation onto a single-tenant model is one of the most expensive changes you can make.

The third is raw performance at scale: a catalog of tens of thousands of SKUs, with stock changing hundreds of times a minute, cannot be served by a schema that was only ever tested with a few hundred items. This is where indexing, partitioning, and a clear separation between the write-heavy ledger and the read-heavy views start to matter. On Lorecs, the multi-region and multi-currency demands forced exactly this kind of discipline, because the same order data had to be correct and fast across regions at once.

Should warehouse inventory run on a monolith or microservices?

Start with a well-structured modular monolith and extract services only where a real bottleneck or team boundary justifies it. Most warehouse systems do not need microservices on day one.

The microservices-by-default instinct has cost more warehouse projects than it has saved. A distributed system buys independent scaling and deployment, but it pays for them with network calls, distributed transactions, and operational overhead that a young product rarely needs. The pattern that ages well is a modular monolith: one deployable, but with firm internal boundaries between inventory, orders, fulfillment, and integration, so that a service can be carved out later precisely where the load or the team structure demands it, rather than everywhere up front.

When you do distribute, an event-driven backbone is what keeps it sane. On Driven, our enterprise CRM and performance platform, the backend combined a monolith and microservices with event-driven processing, and it had to unify data from more than forty third-party integrations into a single live view. The lesson that transfers to a WMS is that components should react to events such as ShipmentDispatched rather than call each other directly, which keeps the pieces decoupled and lets you add a consumer without touching the producer.

This is also where event sourcing enters the picture for the inventory ledger specifically. Because a warehouse already thinks in discrete, ordered facts, storing those facts as an append-only log gives you a complete, replayable audit trail rather than a single mutated row. It is not the right tool for every module, but for the stock ledger of a regulated or high-value operation it is often worth the added complexity.

Read the deep-dive: Event Sourcing for Warehouse Systems →

Which database is right for a warehouse management system?

For the inventory and order ledger, a relational database such as PostgreSQL is the default, because warehouse data is densely related and every stock movement has to stay consistent.

A WMS is, at its core, a ledger: stock moves in and out, orders are raised and fulfilled, shipments are tracked, and money is reconciled at the end. That data is densely relational, with correctness measured across rows rather than within a single record, which is exactly the shape relational databases were built for. We run PostgreSQL with Prisma behind our own RMS platform for precisely this reason: ACID guarantees and row-level locking are what stop two orders from both selling the last unit of a SKU.

That does not make it PostgreSQL for everything. A WMS has softer data too: product catalogs where every category has different attributes, and high-volume, low-relationship event streams like barcode scans. On Driven we ran a polyglot backend with MySQL and MongoDB side by side, letting the document store absorb the parts that refused a fixed shape. The pattern we trust is one clear system of record, almost always relational, with at most one specialized store next to it for the module that genuinely earns it.

The decision is therefore per workload, not per fashion. Choose the store that fits the hottest, most correctness-sensitive part of the system first, which is the ledger, and only split when a specific module clearly fights the relational model. The full head-to-head, including transactions, schema evolution, and reporting, is in the dedicated comparison.

Read the deep-dive: PostgreSQL vs MongoDB for WMS →

How does real-time inventory tracking actually work?

The server commits each stock change and then pushes an event to connected clients over a WebSocket, so screens update the instant something happens instead of polling for it.

Polling cannot deliver a live warehouse. Asking the server every few seconds what changed wastes most of its requests and bakes latency into the design. The push model flips it: the server holds an open WebSocket connection and emits a change the instant it commits. On our own RMS platform we run a Socket.io layer in exactly this shape, where the server is authoritative and emits typed events such as NewNotification to clients, and the client's job is to listen and update, never to broadcast business state to its peers.

Translate that to a warehouse and a handheld scan hits the server, the server commits the change to the ledger, and only then emits an event to every client that cares. The cost of a real-time system is messages multiplied by recipients, so events are scoped into rooms, typically one per warehouse and often one per zone, so a picker in one facility never receives another's traffic. Driven used the same instinct to drive its real-time dashboards, scorecards, and leaderboards from server-side events.

The piece teams forget is scaling across servers. A stock event committed on one server has to reach a client connected to another, which a single process cannot do alone. The fix is a pub-sub broker, commonly Redis, that every server subscribes to, so an event published once is fanned out to all of them. Add reconnection and resync handling for the dead zones every warehouse has, and the live view stops being fragile.

Read the deep-dive: Real-Time Inventory with WebSockets →

How do barcode and RFID scanners connect to a WMS?

Through one of four patterns: the keyboard wedge for most handhelds, the device camera for mobile, Web Serial for RFID readers, and a local bridge for hardware the browser cannot reach.

Scanning is the highest-frequency interaction in a warehouse, so the link between the hardware and the app is the product, not a detail. The default and most underrated pattern is the keyboard wedge: most handheld and USB scanners can act like a keyboard, typing the barcode into the focused field followed by an Enter keypress. The app buffers that rapid burst and recognizes the terminator, and it works in any browser with almost no integration code.

The other patterns cover the cases the wedge cannot. The device camera turns a phone or tablet into a reader for mobile and occasional scanning. Web Serial, WebUSB, and Web Bluetooth handle RFID readers and devices that stream a structured protocol rather than acting like a keyboard. And a small local bridge service covers fixed industrial readers whose vendor only ships a desktop SDK. The right system usually supports two: a wedge for the handhelds doing the bulk of the work, and a camera fallback for everything else.

This is browser-to-device integration, the same discipline we applied on Kragworks, where we wired Mapbox geolocation and field-device data into React and Angular front-ends so readings from the field landed in the UI reliably. Whatever the transport, the data model should treat a scan as an event regardless of how it was captured, so the rest of the system never has to care which device produced it.

Read the deep-dive: Barcode and RFID Integration in React →

How should a WMS integrate with an ERP?

Use REST when you need an immediate answer at moderate volume, and a message queue for high-volume events that must survive the ERP being down. Make every operation idempotent either way.

A WMS rarely lives alone. It tells the ERP what shipped so invoices go out, pulls purchase orders so receiving knows what to expect, and keeps counts agreeing across two systems that run on different rhythms. The warehouse is real-time and physical; the ERP is transactional, slower, and often rate-limited. The integration shape is really a decision about how much you let one system's bad day become the other's.

Synchronous REST is simple and right for moderate volume when you need the result now, and it is what we reach for first. On Lorecs we integrated QuickBooks across two platforms for unified, multi-currency accounting, taking orders and shipments through to invoicing. A message queue inverts the relationship for high-volume, fire-and-forward events: the WMS publishes a message and a consumer applies it to the ERP at its own pace, so the warehouse never stops because accounting is down. On Driven, that same event-driven backbone unified more than forty integrations without a tangle of point-to-point calls.

Whichever transport you choose, the property that matters most is idempotency: processing the same event twice must not create two invoices. We learned how unforgiving that is on Lorecs, where invoices had to be correct enough to pass an external validation check, with the payoff being zero invoice rejections. Add a scheduled reconciliation that compares the two systems and flags drift, because no real-time integration stays perfectly in sync forever.

Read the deep-dive: WMS to ERP Integration →

How do you build a reporting layer that does not slow the warehouse?

Separate the read path from the write path. Offload heavy queries to a read replica, pre-compute expensive aggregates as materialized views, and reach for a columnar store when analytics outgrow the operational database.

Warehouse questions are aggregate questions: stock turnover, fulfillment time, billing reconciliation. Run those heavy, multi-table queries against the same database that is committing live picks and you slow the floor down to produce a chart. The first principle of a reporting layer is therefore separation: keep analytics off the hot transactional path so a slow report never blocks a fast stock decrement.

The standard tools, in increasing order of investment, are read replicas that take query load off the primary, materialized views that pre-compute expensive aggregates so a dashboard reads a prepared answer rather than recomputing it each time, and, when analytics genuinely outgrow the operational database, a dedicated columnar store built for it. On a long-running B2B data platform we maintain, the analytical workload runs on ClickHouse, a columnar database purpose-built for fast aggregation over large volumes, precisely so the operational systems are not asked to do two jobs at once.

The right level depends on scale. A mid-size warehouse may need nothing more than good indexing and a few materialized views; a high-volume, multi-site network benefits from a read replica and, at the top end, a separate analytics store fed from the operational events. The mistake is to skip the separation entirely and let reporting and operations fight over the same connection pool.

How do you deploy WMS updates without downtime?

Keep a healthy pool serving traffic with a rolling or blue-green deployment, and make every schema change backward-compatible so the old and new code can run against the same database during the rollout.

A warehouse has no maintenance window, so updates have to ship while the floor keeps moving. Swapping application servers without downtime is a solved problem with the right pattern: a rolling deployment behind a load balancer replaces instances a few at a time, while blue-green runs two environments and cuts over in one switch for near-instant rollback. We deploy our own systems on AWS, with the API on EC2, PostgreSQL on RDS, and storage on S3.

The genuinely hard part is the database, because during a rollout the old and new code touch the same schema at once. A column renamed in a single step breaks the still-running old code the instant it applies. The discipline that solves it is expand-and-contract: add the new structure, dual-write and backfill, switch reads, and only later remove the old structure, so every step is independently safe to deploy and to roll back.

That discipline is exactly what let us migrate Lorecs from .NET Core 2.1 all the way to .NET 9 without disrupting live operations, and modernize Kragworks from Angular 7 and .NET 2.1 to Angular 17 and .NET 8 while keeping production stable. Neither was possible by taking the system down. Both were possible because every change was made backward-compatible first. Zero-downtime is a habit, not a feature.

Read the deep-dive: Zero-Downtime Deployment on AWS →

Scalable WMS architecture: common questions

Short answers to the questions teams ask when scoping a warehouse build.

Planning a scalable WMS build?

Answer eight questions about your warehouse and our WMS Architecture and ROI Assessment turns this guide into a report for your operation: projected savings, a payback window, and which of these decisions actually apply to you.

More on warehouse management systems

Everything on this topic that lives elsewhere on the site.

TryRun the WMS ROI calculator

Takes a couple of minutes. No email needed to see the result.

Proof

80% fewer manual errors, 50% faster order processing

Project management at Rorix is top-notch. They deliver on time, stay responsive, and adapt to our needs. They don’t just stop when daily tasks are done, they keep refining lower-priority items and actively suggest improvements to better the system.

Moe F, Software Director, LorecsDistribution / Wholesale
Distributor WMS case study