How do you design real-time inventory for quick commerce without overselling?
Short answer: real-time inventory in quick commerce is not a one-minute stock refresh. You need short cart reservations, atomic decrement, TTL, WMS events, idempotent checkout, release after timeout and a UI that shows availability only for the right dark store or micro-warehouse.
First definition: real-time inventory is a business promise
In quick commerce, the customer is not only buying a product. They are buying certainty: "this is available near me and will arrive in minutes". If the app accepts payment for an item the dark store no longer has, the problem does not end with a refund. Support cost rises, app trust drops, the courier moves without value and marketing pays again to recover the same customer.
That is why real-time inventory cannot be treated as a warehouse report. It is part of the shopping experience and checkout. Stock visible in the app must consider customer location, the right warehouse, products in other carts, active reservations, payments, cancellations, pick pack, substitutions and WMS/ERP integration delays.
At GMI Software we design q-commerce as a domain system: React Native or Next.js for a fast front end, MedusaJS where commerce core fits, NestJS for reservation rules and integrations, Redis for short locks, and PostgreSQL/WMS/ERP as the truth and audit layer. Redis speed alone is not enough if you do not know when the lock was created, who released it and how to reproduce the order after failure.
Overselling: where the bug actually starts
Overselling rarely comes from one "slow endpoint". It is usually a chain of delays: the app shows cached stock, the cart does not reserve the item, payment takes dozens of seconds, WMS sends an update after picking, and ERP corrects in batches. During that window, the last unit can sit in three carts, on a picker terminal and inside a push promotion.
The classic mistake is updating stock only after payment. In q-commerce, that is too late. The item must be reserved or marked as held when the customer enters the real checkout path. That reservation needs a TTL because some carts are abandoned, some payments fail and some orders require substitution.
The second mistake is not separating on hand, available, reserved and committed. "We have 10 units" means little if 4 are in carts, 2 are assigned to orders in picking, 1 is damaged and 3 are available only in another dark store. Real-time inventory must calculate availability, not only physical stock.
Architecture map: from WMS to the Buy button
The healthiest model separates responsibilities. WMS or ERP remains the source of truth for physical stock and corrections. The inventory service calculates availability in the context of warehouse, channel and reservations. Redis holds short locks and counters with a very short lifetime. The event bus broadcasts changes. The frontend only shows what is available for the specific address and delivery window.
The visual below shows the flow. Read it left to right: stock event from WMS/ERP, availability service, Redis reservation with TTL, cart/checkout, payment/order commit and live UI through WebSockets or server-sent events. Each step has its own failure mode and its own metric.
Cart hold: short reservation instead of blocking stock forever
Cart reservation must be short, explicit and reversible. In practice this means TTL measured in minutes, not hours. For q-commerce, 3-10 minutes is often enough to complete checkout and payment. If payment does not return in time, the lock expires and the product returns to availability. If payment succeeds, the reservation becomes a committed order.
Redis fits this layer because in-memory operations are fast, and commands such as SET with NX/EX options can create simple locks with expiration. But a Redis lock is an operational mechanism, not the accounting ledger. Final order state, audit and settlement must land in durable storage and finance/warehouse systems.
The key detail is atomicity. You cannot first check "is it available" and then reserve in a separate step if another customer can do the same between those calls. You need atomic decrement, transaction, Lua script or a service that serializes the decision per SKU/location. Otherwise the real-time UI only shows inconsistency faster.
MedusaJS Inventory: useful commerce core, but q-commerce rules are domain logic
Medusa has an Inventory Module for managing inventory items, stocked quantity, reserved quantity, location levels and availability by stock location. That is a useful base when building headless commerce with multiple warehouses, sales channels and custom storefronts. It also gives the API and modularity needed to integrate an external WMS.
But q-commerce needs rules beyond a standard catalogue. Availability depends on customer address, delivery SLA, courier capacity, picking time, minimum thresholds, substitutions, channel priority, promotion and whether an item is already physically in a pickers basket. We usually keep that logic in NestJS or a custom service above MedusaJS instead of hiding it in the frontend.
A good API should answer business questions, not only technical ones: "can this customer at this address buy 2 units now?", "how long do we hold the reservation?", "what do we show if the last unit is in another customer cart?", "can we suggest a substitute?".
Live UI: WebSockets help, but they do not replace consistency
The WebSocket API opens a two-way session between browser or app and server. For q-commerce, that naturally fits live stock, order picking status, courier ETA and substitution messages. Instead of polling, the app can receive an event: "SKU unavailable", "reservation expired", "order accepted".
But WebSockets do not solve overselling. If the backend accepts two checkouts for the last unit, the live UI only tells one customer about failure faster. The order matters: consistent reservation and idempotent checkout first, live notification layer second.
On mobile you also need to design for offline mode, poor network and resume after the app sleeps. React Native should not trust local cart state when the user returns from background. On resume, the app should refresh availability and reservation status from the backend before allowing payment to continue.
Checkout: idempotency, release and reconciliation
Q-commerce checkout has several states: reservation created, payment pending, payment succeeded, order committed, picking started, reservation released, substitution needed, cancelled. If you treat it as one "place order" request, payment failures, client retries and provider timeouts quickly create duplicate orders or dead reservations.
An idempotency key is mandatory for finance and inventory operations. The same checkout retried by the app after timeout must not take stock twice. A payment webhook can also arrive again and should not create another order. Every state transition must be retry-safe.
You also need a reconciliation job: a process that finds reservations past TTL, payments without orders, orders without WMS confirmation and differences between inventory service and the system of truth. Real-time inventory without reconciliation looks good in a demo, but starts leaking after the first promotion weekend.
Operational metrics: what to watch every day
You cannot run q-commerce without inventory metrics. The minimum set is oversell rate, reservation expiry rate, payment timeout rate, WMS event lag, ERP sync lag, stock correction count, substitution rate, cancelled order rate, unavailable-after-click rate and manual intervention count. Each metric needs an operational owner, not only a technical dashboard.
In practice, tails hurt more than averages. Average WMS lag can be 300 ms, while single 20-second spikes during a promotion destroy checkout. That is why we monitor percentiles, queues, retries, DLQs, time from add-to-cart to payment success and the difference between availability shown to the customer and state at commit time.
For leadership, a simple business dashboard is better: how many orders reservations saved, how many products were released after timeout, how many orders required substitution and how many refunds came from stock errors. That turns architecture into an operational result.
Implementation cost: what really increases scope
Real-time inventory cost is not mostly about Redis itself. It depends on warehouse count, WMS/ERP API quality, sales channels, mobile requirements, substitution rules, delivery SLA, payments, returns, courier roles, promotions and observability. A simple MVP may have one warehouse and a short hold. A dark-store network needs geofencing, routing and more complex rules.
A sensible first q-commerce scope for mobile and backend often starts around PLN 180,000-320,000: DDT, inventory service, cart reservation, Redis TTL, WMS/ERP integration, checkout idempotency, React Native/Expo or Next.js, monitoring and load tests for critical paths. A larger warehouse network, courier dispatch, marketplace or multi-channel model increases scope.
At GMI we can move to fixed price after DDT because we know systems of truth, integrations, failure modes, volume and MVP priorities. Without DDT, q-commerce estimation is guesswork: everything looks simple until two checkouts fight for the last product.
How GMI designs real-time inventory
We start with the process, not the tool. We map where stock comes from, when it is reserved, who can change it, what happens after cancellation, how substitution works, when the customer sees "unavailable" and how warehouse operations see the same cart. Only then do we choose Redis, MedusaJS, NestJS, queues, WebSockets and the data model.
Technically, we often combine React Native/Expo for the app, MedusaJS as commerce core, NestJS as inventory/reservation service, Redis for short locks, PostgreSQL for durable state, an event queue for WMS/ERP and observability for lag and retries. What matters is that reservation logic is testable and independent from one frontend.
For the client, that means fewer operational losses, fewer refunds, better retention and a product that can scale beyond the first warehouse. Source-code ownership and no vendor lock-in matter especially here because inventory rules are the heart of the business, not a store add-on.
Sources and further reading
Medusa Inventory Module - inventory items, stocked quantity, reserved quantity and stock locations: https://docs.medusajs.com/resources/commerce-modules/inventory
Medusa Inventory concepts - reservations and inventory levels: https://docs.medusajs.com/commerce-modules/inventory/concepts
Redis command SET - NX/EX options used for simple expiring locks: https://redis.io/docs/latest/commands/set/
Redis distributed locks pattern: https://redis.io/docs/latest/develop/clients/patterns/distributed-locks/
MDN WebSocket API - two-way communication sessions between client and server: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API
GMI event-driven commerce guide: https://gmi.software/blog/event-driven-commerce-redis-rabbitmq-sqs
GMI React Native app store launch checklist: https://gmi.software/blog/react-native-app-store-launch-checklist
GMI MedusaJS development service: https://gmi.software/services/medusajs-development
GMI mobile apps service: https://gmi.software/services/mobile-apps
Frequently asked questions
- What is overselling in q-commerce apps?
- Overselling means accepting an order for a product that is no longer available in the relevant dark store or delivery window. In q-commerce it usually comes from missing cart reservations, WMS/ERP lag, payment retries or cached stock shown as current.
- Why is a plain ecommerce-to-ERP link not enough?
- ERP is usually not designed to handle hundreds of short cart locks per second. It should remain the system of truth for stock and corrections, but q-commerce needs a separate inventory/reservation service, WMS events and a fast lock layer such as Redis.
- Is Redis enough for real-time inventory?
- Redis is excellent for short locks, TTL and fast counters, but it should not be the only truth for orders. You need durable storage, idempotent checkout, WMS/ERP integration and a reconciliation job that finds dead reservations and stock differences.
- How do WebSockets help mobile commerce?
- WebSockets can push stock changes, reservation expiry, picking status and ETA without constant polling. They do not replace a consistent backend: if checkout is not idempotent, live UI only shows the error faster.
- For q-commerce should you pick Shopify or MedusaJS?
- If the process is standard, SaaS may be enough. If you have many dark stores, cart reservations, custom WMS/ERP, substitutions and aggressive delivery SLAs, MedusaJS + NestJS gives more control over APIs, code and inventory rules without vendor lock-in.
- How much does real-time inventory implementation cost in q-commerce?
- A sensible first mobile + backend scope often starts around PLN 180,000-320,000: DDT, inventory service, cart reservation, Redis TTL, WMS/ERP, idempotent checkout, React Native/Expo or Next.js, monitoring and load tests. Multi-warehouse networks, courier dispatch and marketplace flows increase scope.
Content updated: July 11, 2026