50,000 free calls a month, card-free. Get an API key →

Documentation menu
docs / adr · raw .md

Truck and ADR routing

What a lorry may legally drive is not a preference, it is a set of rules. This page states exactly which of those rules our routing enforces, which it does not, and where the data comes from, so you can check our answers against the standards rather than take them on trust.

Two sources are normative here:

  • ADR 8.6.4, the tunnel restriction provisions of the European Agreement concerning the International Carriage of Dangerous Goods by Road (UNECE, public).
  • Council Directive 96/53/EC, which sets the maximum authorised dimensions and weights for vehicles in international traffic.

What is enforced

Send costing: "truck" with a truck profile. Every field below is passed to the routing engine and applied to the graph search, so a restricted way is not merely penalised, it is excluded.

FieldUnitSent
heightmetresalways
widthmetresalways
lengthmetresalways
weighttonnes, gross combinationalways
axle_loadtonnes, heaviest single axlewhen supplied
axle_countcountwhen supplied
hazmatbooleanalways
adr_tunnel_codeADR 8.6.4 codewhen supplied

Omit axle_load or axle_count and no axle constraint is applied. We do not guess them, because a guessed axle load is worse than none: it would silently exclude legal roads or admit illegal ones, and you would have no way to tell which.

Defaults

An omitted dimension falls back to the Directive 96/53/EC maximum for a standard articulated vehicle: 4.0 m height, 2.55 m width, 16.5 m length, 40 t gross weight. These are deliberately the legal maxima rather than a typical vehicle, so an unspecified request errs towards over-restriction. A route we return for the defaults is drivable by anything smaller.

ADR tunnel categories

Tunnel categories run A to E. Category A carries no restriction. Categories B to E progressively exclude loads by their tunnel restriction code.

check_adr_tunnel answers one question: may a load carrying tunnel code X pass through a category Y tunnel? It is a pure lookup against the ADR 8.6.4 matrix. It performs no network call, consults no map data, and is therefore free to run and identical for everyone.

Two deliberate choices, both conservative:

  • A declared code is read at its worst case. Where a code covers several transport categories, we apply the most restrictive reading.
  • hazmat: true with no declared code is treated as code B, the broadest restriction, rather than assumed unrestricted.

Both choices can refuse a passage that a more precise declaration would permit. That is the intended direction of error. If you need the less restrictive answer, declare the code.

Which engine, and what each needs

The gateway runs on one of two routing engines, and the ADR support differs. This matters if you self-host.

  • GraphHopper backend: ADR tunnel enforcement needs no modified engine. Forbidden categories are emitted as custom-model rules against GraphHopper's own hazmat_tunnel encoded value, using the stock server.
  • Valhalla backend: dimensional and hazmat constraints work on a stock build, but adr_tunnel_code requires our bounded ADR costing fork. On an unmodified upstream Valhalla the field is ignored, and no tunnel-category restriction is applied.

That fork is the single piece of engine code we modify, it is scoped to ADR tunnel-category costing alone, and the change has been offered upstream. See licensing and the lineage table in the repository for how every component is consumed.

If you self-host on stock Valhalla and need tunnel-category enforcement, either run the GraphHopper backend or use our distro build. Do not assume the field took effect: check that a code D load is refused a category E tunnel on a route you know.

Limits, stated plainly

Restrictions come from OpenStreetMap, and OSM truck tagging is uneven. Height, weight and hazmat tags are well populated on some networks and sparse on others. Where a restriction is not tagged, no engine can honour it, including ours. We publish a truck-attribute completeness audit for exactly this reason, so the gaps are measurable rather than assumed away.

This is a routing engine, not a compliance certificate. We tell you what the map and the ADR matrix say. We do not certify that a vehicle, load or journey is lawful, and we do not issue clearance documents. The duty holder remains the operator and, where appointed under ADR 1.8.3, their Dangerous Goods Safety Adviser.

Speed limits and restrictions are never fabricated. If the graph does not carry a value, nothing is surfaced rather than a plausible guess.

Using it

  • POST /route with costing: "truck", see the API reference.
  • POST /optimise carries the same constraints through multi-vehicle planning, see optimisation.
  • Agents can call route and check_adr_tunnel as tools over the MCP server.
  • Tunnel code tables and parameter conventions are on the conventions page.