Deadhead Distance & Duration

What is Deadhead Travel?

In fleet operations, deadhead travel refers to the distance and time a vehicle travels without a passenger, cargo, or active task — essentially, empty running. This happens on two legs of every trip: the first leg (from the depot or trip's starting location to the first task with zero load) and the last leg (from the last task back to the depot or trip's end location with zero load).

Unconstrained deadhead travel inflates fuel costs, increases vehicle wear without generating any revenue to offset them, essentially reducing the productive utilisation of your fleet. For operations that span large geographies — field services, technician dispatch, NEMT, or last-mile logistics — small deadhead travels each day compound into significant operational costs over time.

The Route Optimization API's Deadhead Distance & Duration feature lets you set explicit limits on how much unloaded travel each vehicle is allowed to perform. The optimizer then factors these limits into the route-planning process, favouring assignments that keep deadhead within budget — without sacrificing overall service coverage.

Use Case: Field Service Technician Dispatch

Consider a field service company managing a fleet of technicians across a metropolitan area. Each technician starts their shift from a designated location, visits multiple customer sites for repairs or appliance delivery, and ends their day either at a designated location or at the last task.

The operations team has identified that excessive empty driving — technicians travelling far before their first job or after their last — is eroding profitability and causing schedule overruns. They want the optimizer to generate routes where:

  • Either the technician does not drive more than 1,000 metres unloaded to reach their first task.
  • Or they do not drive more than 1,500 seconds unloaded after completing their last task.
  • If a route unavoidably breaches these limits, then add penalty points. The solution with the fewest total penalty points is selected.

This is exactly the scenario the Deadhead Distance & Duration feature is built for.

How do Deadhead limitations work?

Deadhead limits are implemented as a soft constraint in the optimizer. This means the optimizer will always produce a fully assigned solution — even if no route plan can satisfy the deadhead limits for every vehicle. In that scenario:

  • The optimizer still assigns tasks to vehicles.
  • Each violation of the deadhead limit adds a penalty score to the solution cost.
  • The solution with the lowest total penalty score across all vehicles is chosen as the final output.

When Deadhead Is Calculated?

Only for the first and last legs of a trip where the vehicle is not carrying any load are counted towards the deadhead. Intermediate legs between tasks are not considered deadhead travel. The rules for which legs count depend on the job type:

Task TypeFirst Leg (Depot → First Task)Last Leg (Last Task → Depot)
General (shipments / only service jobs)✅ Counted✅ Counted
At least one Delivery job (cargo loaded from start)❌ Not counted (vehicle is loaded)✅ Counted
At lease one Pickup job (cargo in vehicle until trip ends)✅ Counted❌ Not counted (vehicle is loaded)

Configuring the Feature: Input Parameters

All deadhead parameters are set at the vehicle level. The table below summarises the four available fields:

ParameterTypeDescription
max_deadhead_distanceinteger (metres)Maximum deadhead distance allowed per vehicle trip (first + last leg combined, where applicable).
max_deadhead_durationinteger (seconds)Maximum deadhead duration allowed per vehicle trip.
costs.deadhead_distance_penaltyintegerPenalty score added per unit of deadhead distance that exceeds the specified limit. Higher values push the optimizer harder to stay within the limit.
costs.deadhead_duration_penaltyintegerPenalty score added per unit of deadhead duration that exceeds the specified limit. Higher values push the optimizer harder to stay within the limit.

In the field service example above, the two vehicles are configured as follows:

VehicleMax Deadhead Dist.Max Deadhead Dur.Distance PenaltyDuration Penalty
Vehicle 11,000 m-1,000 / unit-
Vehicle 2-1,500 s-2,000 / unit

Example API Request & Response

Example API Request

The request below sets up two technician vehicles with different deadhead budgets and penalty costs, serving a mix of service tasks and shipments across Los Angeles:

1
curl --location 'https://api.nextbillion.io/optimization/v2?key=<your_api_key>' --header 'Content-Type: application/json' --data '{...}'

Example API Response

The condensed response below shows the routes generated for both vehicles. All tasks are assigned (”unassigned”: 0). Note the penalty.deadhead field on Vehicle 1's route — this signals a deadhead constraint violation:

1
{
2
"description": "Deadhead Example",
3
"result": {
4
"code": 0,
5
"summary": {...},
6
"routes": [...]
7
},
8
"status": "Ok"
9
}

Interpreting the Output

To understand deadhead impact, examine the first and last steps of each route — specifically the distance and duration values at those steps — and compare them against the vehicle's configured deadhead limits. The route-level penalty.deadhead field in the response is the definitive signal: if it is present, the constraint was breached; if absent, the vehicle's route satisfied its deadhead limits.

VehicleDeadhead TypeFirst-leg DeadheadLast-leg DeadheadDeadhead TotalLimitpenalty.deadhead
Vehicle 1Distance1,257 m for Task 10 m (no end depot)1,257 m1,000 m257,000 ⚠️
Vehicle 2Duration0 sec (no start depot)328 sec from Shipment Delivery 3 to the end location.328 s1,500 sec0 ✅

Vehicle 1 Analysis

Route: Depot → Task 1 → Shipment Pickup 1 → Shipment Delivery 1 → End

  • The first task is a general service job (Task 1) — neither a delivery nor a pickup type. This means the first leg fully counts towards deadhead.
  • First-leg distance from the start location (index 0) to Task 1 (index 1) = 1,257 m; exceeding the 1,000 m limit by 257 m.
  • No end_index is defined, so the trip ends at the last task's location (Shipment Delivery 1, location_index: 3). Last-leg deadhead = 0 m.
  • Total deadhead = 1,257 m. The response reports penalty.deadhead: 257,000 i.e. the optimizer’s accumulated penalty cost for this violation.
  • Despite the penalty, the optimizer assigned this route because it produced the lowest total penalty across the solution as a whole.

Vehicle 2 Analysis

Route: Start → Shipment Pickup 2 → Shipment Delivery 2 → Shipment Pickup 3 → Shipment Delivery 3 → End depot

  • Vehicle 2 has no start_index defined. Its trip effectively begins at the first task's location, so first-leg deadhead = 0 m.
  • The route ends at a designated end location (index 8). The cumulative duration at the end step (2203 s) is 328 s more than the duration at the previous step (1875 s). Deadhead for last leg ≈ 328 s.
  • Total deadhead = 328 s, while the deadhead limit is 1500 s. No penalty.deadhead field appears in the response since the deadhead constraint is fully satisfied.

What We Learned?

This example illustrates several important takeaways about how the Deadhead Distance & Duration feature behaves in practice:

  • Task type determines which legs count. Pickup and delivery jobs have specific exemptions — always account for your task mix when setting deadhead limits. As seen here in our example, Task 1 being a general job meant its first leg was fully counted.
  • Depot configuration shapes deadhead exposure. Vehicles without a defined start or end depot automatically have zero deadhead on those respective legs.
  • Penalty scores are a tuning lever. Vehicle 2's higher penalty (2,000 vs. 1,000 for Vehicle 1) made its deadhead violations more costly to the optimizer. The optimizer therefore accepted the 257,000-point penalty on Vehicle 1 rather than forcing a comparable violation on Vehicle 2, demonstrating that penalty values directly influence which vehicle absorbs the trade-off when constraints cannot be fully met.
  • Soft constraints guarantee full coverage. Unlike hard constraints that can leave tasks unassigned, deadhead limits as soft constraints ensure every task is served — violations are penalised, not blocked. In our example, the summary's unassigned: 0 confirms that all tasks were successfully covered despite the Vehicle 1 violation.
  • Use penalty scores to audit violations programmatically. The presence of a route-level penalty.deadhead value in response is the definitive indicator that a vehicle's deadhead limit was breached. Its absence, as with Vehicle 2 in this example, confirms the constraint was satisfied. Build this check into your solution validation logic.

Explore other powerful features that the NextBillion.ai’s Route Optimization API can solve seamlessly.