Series · 7 parts Published June 29, 2026

Delivery route planner

Every morning a small delivery or service business has the same puzzle: a list of stops, one or two vans, and no good way to put them in order beyond a driver’s memory and a paper map. The result is doubled-back miles, stops missed inside their time window, and customers ringing to ask when the van will turn up. This is the design of a small serverless planner that gathers the day’s stops, geocodes the addresses, works out a sensible order — fewest miles, time windows honoured, the van not overloaded — and hands the driver a clean manifest while telling each customer a real ETA window that updates as the round runs. The optimising is plain code; a model only drafts the customer wording, and the plan is always a proposal the driver can override. Seven posts on the same system — one diagram at a time — with an engineering reference at the end.

  1. 01

    A delivery route planner on AWS for a few dollars a month

    The whole system on one page — gather the stops, optimise the order, build the manifest, send the ETAs — plus the guardrail that the route is a proposal and plain code, not a model, does the optimising.

  2. 02

    How the day’s stops get gathered

    How the day’s stops become a clean, geocoded list — reading the orders mirror, turning addresses into coordinates with a cache, and validating time windows and capacity before any routing happens.

  3. 03

    How a route gets optimized

    How a list of stops becomes a sensible order — the distance matrix, a nearest-neighbour seed, 2-opt to uncross the route, and time windows and capacity enforced as hard constraints. A worked example, and an honest note on what the heuristic does and doesn’t promise.

  4. 04

    How a driver manifest gets built

    How the optimised route becomes something a driver can actually use — an ordered manifest with addresses, access notes, and time windows, rendered to a PDF in S3 and sent as a link, with the driver free to re-order or skip.

  5. 05

    How customer ETAs get sent

    How each customer gets a real ETA window and how it stays honest — one Bedrock-drafted message per stop, driver check-offs flowing back through EventBridge, and the remaining ETAs recomputed from where the van actually is.

  6. 06

    What the delivery route planner costs

    A line-by-line monthly cost at about $3.10 for roughly 1,000 stops, where the money actually goes — the geocoding and matrix API is the main variable — and what the bill looks like at higher volume.

  7. 07

    Engineering reference: the delivery route planner architecture

    The same system drawn for engineers — the Lambda inventory, the EventBridge Scheduler build and the check-off events, DynamoDB tables and key schemas, S3, SES and SNS, IAM scope, the region, and the routing and geocoding service.

What is a delivery route planner?
A small serverless system that turns the day’s delivery or service stops into an ordered driver route. Each morning it gathers the stops, geocodes the addresses, and works out a sensible order — fewest miles, time windows honoured, the van’s capacity respected. It builds a driver manifest (ordered stops, addresses, access notes) and sends each customer an ETA window that updates as the driver checks off stops. The route is a proposal the driver can re-order or skip; nothing is dispatched automatically.
How much does it cost to run?
About $3.10/month at a typical small-round volume — roughly 40 stops a day, around 1,000 a month. Nothing runs when there are no stops to plan, so the fixed cost is essentially zero. The single biggest line is the geocoding and distance-matrix API; addresses repeat day to day, so a cache keeps most of those calls free. Customer ETA SMS, if you send them through SNS, carry a per-message carrier fee that sits outside this total — email ETAs through SES are effectively free.
Which AWS services does it use?
Lambda (Python 3.14, arm64), EventBridge Scheduler for the morning build and EventBridge for driver check-off events, DynamoDB on-demand (stops, routes, driver progress), S3 (manifest PDFs and the geocode cache), SES and SNS for customer ETAs, SQS with a dead-letter queue, Secrets Manager for the geocoding/matrix API key, CloudWatch Logs at 7-day retention, AWS Budgets, and Bedrock (Claude Haiku 4.5) only to draft the customer wording. No API Gateway, no NAT Gateway, no always-on compute. One region, eu-west-2.
How does it optimize the route?
Plain code, not a model. It builds a distance-and-time matrix between the depot and every stop — from a hosted matrix service, or a straight-line estimate as a fallback — then seeds a route with nearest-neighbour (start at the depot, always hop to the closest unvisited stop) and improves it with 2-opt, which repeatedly uncrosses pairs of legs that overlap. Time windows and vehicle capacity are honoured as hard constraints: a swap that would make a van late or overloaded is rejected. It’s a strong, fast heuristic for the dozens-of-stops range — not provably the shortest possible route, but reliably close, in milliseconds.
Does it use AI?
Only for words. The whole optimisation — the matrix, the nearest-neighbour seed, the 2-opt passes, the time-window and capacity checks — is plain Python with no model anywhere near it. Bedrock Claude Haiku 4.5 fires once per customer message, purely to turn the already-computed ETA window and stop details into a friendly sentence. The route the driver follows never depends on a model, and you can switch the wording to a fixed template and drop AI entirely.
Can the driver override the planned route?
Yes — the plan is a proposal, never an instruction. The manifest is the suggested order, and the driver is free to re-order stops, skip one, or insert an emergency call. As stops are checked off the system follows the driver’s actual progress rather than forcing the original sequence, and it recomputes the remaining ETAs from where the van really is. Nothing is dispatched or committed automatically; a human is always driving, literally and figuratively.
All posts