June 12, 2026 · 6 min read · Data
Tokyo's 23 special wards: not boroughs, not cities, something else.
Tokyo doesn't have a mayor. It has a governor of Tokyo Metropolis, plus 23 special-ward mayors, plus 26 city mayors, plus a handful of town and village heads. There is no single municipal entity called "Tokyo." Every travel app pretends there is, and so must your data.
The legal structure
Tokyo Metropolis (Tōkyō-to) is a prefecture. Inside it sit:
- 23 special wards (tokubetsu-ku): Chiyoda, Chuo, Minato, Shinjuku, Bunkyo, Taito, Sumida, Koto, Shinagawa, Meguro, Ota, Setagaya, Shibuya, Nakano, Suginami, Toshima, Kita, Arakawa, Itabashi, Nerima, Adachi, Katsushika, Edogawa. Each has its own mayor, ward office, and budget. Legally they're closer to cities than to boroughs.
- 26 western cities: Hachioji, Tachikawa, Musashino, Mitaka, etc. Suburban-to-rural municipalities that nobody calls "Tokyo" outside of postal addresses.
- 5 towns and 8 villages: Including the Izu and Ogasawara island chains, which are legally Tokyo but 1,000 km offshore.
When a tourist says "Tokyo," they mean the 23 wards plus maybe Mitaka (for Ghibli Museum) and Tachikawa (sometimes, for Showa Memorial Park). They almost never mean Hachioji or the Ogasawara Islands.
Why this breaks naive APIs
A flat city table that treats Shibuya, Shinjuku, and Minato as separate top-level cities (because legally they are) will fail on every "Tokyo" query. The user types "best ramen in Tokyo," your code looks up city_id for "Tokyo," gets back nothing or the prefecture-level row with no venues attached, and returns an empty list.
A flat city table that treats only "Tokyo Metropolis" as the entity has the opposite problem: every venue is attributed to the prefecture, you can't distinguish Shibuya from Adachi, and your "near me" queries lose all neighborhood-level granularity.
Both are wrong. The correct shape is a hierarchical city that exposes a Tokyo entity for human-facing queries while preserving ward-level attribution underneath.
What the API returns
GET /v1/cities/tokyo
{
"city_id": "tokyo",
"name": "Tokyo",
"iso_alpha2": "JP",
"aggregates_neighborhoods": true,
"child_city_count": 23,
"tier": 1,
"context": {
"airport": { "iata": "HND", "name": "Haneda" },
"currency": "JPY",
"timezone": "Asia/Tokyo"
}
}
A query for restaurants in Tokyo fans out across all 23 wards, ranks them globally, and returns the top results tagged with their actual ward:
GET /v1/restaurants?city_id=tokyo&limit=5
[
{ "name": "Sukiyabashi Jiro Honten", "tier": "1 Star", "ward": "Chuo" },
{ "name": "Kanda", "tier": "3 Stars", "ward": "Minato" },
{ "name": "Quintessence", "tier": "3 Stars", "ward": "Shinagawa" },
{ "name": "Ryugin", "tier": "3 Stars", "ward": "Chiyoda" },
{ "name": "Ishikawa", "tier": "3 Stars", "ward": "Shinjuku" }
]
The same pattern, elsewhere
Tokyo isn't unique in being legally fragmented:
- Seoul: 25 autonomous districts (gu) plus a Special Metropolitan City status that makes it co-equal with provinces.
- Berlin: A city-state, simultaneously a city and one of the 16 federal Bundesländer.
- Vienna: A federal state and a municipality in the same body.
- Shanghai & Beijing: Province-level municipalities that report directly to Beijing.
- Brussels: 19 communes that together form the Brussels-Capital Region. Tourists never distinguish.
For each, aggregates_neighborhoods: true is the
flag that says "treat this as one city for query purposes,
even though the law says otherwise." The
child_city_count tells you how big the union is.
One practical caveat
The 23-ward rollup excludes the western cities and the islands. If your user is genuinely planning a trip to Hachioji or Ogasawara, the right call is to query those as separate cities. The Tokyo rollup is a tourist abstraction; don't confuse it with administrative truth, and don't confuse administrative truth with what tourists need.