Beer route-to-market
The truck that delivers full and returns empty-handed
The truck leaves full and comes back empty-handed because two systems own the same trip and never talk to each other. A routing tool plans the outbound drop; a separate returnables ledger tracks the empties. At planning time the router has no idea how many crates or kegs each outlet is holding, so the pickup is guessed, deferred, or skipped. The fix is to plan the drop and the pickup as one event, off one shared stream of per-outlet balances.
Why does the delivery truck come back empty-handed?
In returnable-heavy markets the empties are the asset. Returnable glass bottles (RGB), kegs and crates carry a deposit, sit on your balance sheet, and only earn their keep if they cycle. A refillable glass bottle can be reused 50 times or more - but only if it comes home. Yet the system that knows where those empties are is almost never the system that plans the truck.
The returnables balance lives in a spreadsheet, a depot whiteboard, or a neglected corner of the ERP that can't reliably tell you who is holding your kegs. Routing runs in a separate vendor tool that optimizes the outbound load by weight and volume. It never reads an empties-balance-per-outlet, so it sends the truck out with no pickup instruction, or with last month's count. The driver arrives, the outlet has forty crates stacked and waiting, and the truck is already full or the route won't absorb the detour. The empties stay put. The balance grows. So does the deposit you have written off in all but name.
What does a blind return leg actually cost?
The return leg is the cheapest capacity you own: the truck is already driving back to the depot. Across the industry, empty running is not a rounding error - the American Transportation Research Institute puts deadhead at 15-20% of trucking miles, and in parts of the EU empty vehicle-kilometres run over 30%. For a general carrier that is waste to shave. For a brewer running returnables it is worse: the empty leg is a scheduled asset-recovery run you have already paid for and are choosing not to use.
The scale is not marginal. Large global brewers move upwards of 30% of their volume in refillable containers. Every crate that doesn't return is a deposit refund you can't reconcile plus a replacement unit you buy new. Multiply a handful of stranded crates per outlet across thousands of outlets and several weekly visits, and the "return empty" habit quietly funds a second fleet you never approved.
| Planned as two systems | Planned as one flow |
|---|---|
| Router optimizes the outbound load only | Router sizes the vehicle for drop and expected empties |
| Empties balance is a nightly file, stale by dawn | Empties balance is a live per-outlet projection |
| Pickup guessed or skipped at the door | Pickup is a planned line item on the stop |
| Return leg runs empty | Return leg runs as asset recovery |
Why won't a nightly integration fix it?
The usual reflex is to integrate: export the returnables ledger every night and feed it to the router. It doesn't work, because the empties balance is an event-time number. It changes every time a driver drops, every time a driver picks up, every time an outlet reports a count. A nightly batch is already stale when the 5 a.m. route build reads it, and the plan bakes in yesterday's picture for a run that happens tomorrow.
The balance is also fragmented before it is stale. The distributor's van collected a dozen crates yesterday that never reached your central ledger, because your distributors know your outlets better than your systems do. The driver logged the last three pickups in a signal-dead backyard, so they queued on a handheld that can't assume 4G in the fragmented trade. Wiring two systems-of-record together just moves stale, partial data faster. It never makes the planner and the ledger agree on the same number at the same instant, which is the one thing that lets you plan a pickup with confidence.
How do you fix it: plan the drop and the pickup as one event
Stop treating the return leg as a separate problem. Make delivery and returnables one flow on one event stream, and plan both ends of the trip together.
- Make the balance an event, not a table. Every drop, pickup and outlet-reported count publishes to a shared stream. The balance-per-outlet becomes a projection off that stream that any service can subscribe to, rather than a spreadsheet someone updates on Fridays.
- Have the route service subscribe, not import. When the planner builds tomorrow's run it reads the current projected empties balance for each stop straight from the stream. No overnight file, no re-keying, no dawn staleness.
- Plan the stop with two line items. The optimizer sizes the vehicle for the outbound drop and the expected empties together, so the truck isn't full when it arrives and the return-leg capacity is reserved before the wheels turn.
- Push the expectation to the handheld, capture the actual. The driver sees the expected balance, counts what is really there, and the delta publishes back to the same stream - offline-tolerant, so a dead-signal yard doesn't lose the count. The projection self-corrects on the next sync.
- Close the loop to finance without a re-key. The same empties event updates deposit liability. Your SAP financial core stays the system of record for money; the event stream is the system of record for movement, and the two reconcile continuously instead of at month-end.
- Measure the return leg. Track recovered empties per return-kilometre and the age of each outlet's balance, not just outbound drop performance. If your KPIs only reward the drop, the pickup will always lose.
None of this needs a rip-and-replace. It needs the delivery service and the returnables ledger to read and write the same events instead of guarding private tables - which is the whole premise of running the suite on one event bus rather than a stack of point tools stitched together after the fact.
Deposit-return schemes are widening and packaging rules are tightening, and the empties balance is drifting from a warehouse afterthought toward a number the route optimizer, the finance team and the sustainability report all expect to pull from the same place. The brewers who handle that gracefully won't be the ones who bought the cleverest routing engine. They'll be the ones whose delivery and returnables were never two systems to reconcile in the first place.
Frequently asked questions
Why does my delivery truck return empty when outlets have empties waiting?
Because the router and the returnables ledger are separate systems. At plan time the router never reads each outlet's empties balance, so it dispatches the truck with no pickup instruction or a stale count. The truck arrives full or off-route, and the empties stay put.
Won't a nightly sync between routing and the returnables system fix it?
No. The empties balance is event-time - it changes on every drop, pickup and outlet count. A nightly batch is stale by the 5 a.m. route build, and it arrives fragmented, missing pickups your distributors and offline drivers captured but never posted centrally.
How do you plan delivery and empties pickup as one flow?
Publish every drop, pickup and count to a shared event stream, expose a live per-outlet balance projection, and have the route service subscribe to it. The optimizer then sizes each vehicle for the outbound load and expected empties together, and reserves return-leg capacity before dispatch.
Stuck with exactly this?
BrewOS builds the full route-to-market stack for global brewers — order capture, stock, loyalty, returnables, delivery and analytics on one event bus, run by a team of ~20 engineers. Bring us the feature that’s been stuck the longest and we’ll show you how we’d ship it in days.
Book a 30-minute walkthrough