import type { CountrySummary } from "@dci/core"; import type { Metadata } from "next"; import Link from "next/link"; import { EstimateMark } from "@/components/ui/badge"; import { Page, PageHeader } from "@/components/ui/card"; import { cn } from "@/components/ui/cn"; import { CountryFlag } from "@/components/ui/country-flag"; import { EmptyState, OfflineNotice } from "@/components/ui/states"; import { RowLink, TBody, THead, Table, Td, Th, Tr } from "@/components/ui/table"; import { api } from "@/lib/api"; import { fmtInt, fmtMw, fmtPct, pluralize } from "@/lib/format"; import { routes } from "@/lib/routes"; import { compareBy, hrefWith, parseSort, sortTh, spGet, type SearchParams, type SortState } from "@/lib/sort"; export const revalidate = 120; export const metadata: Metadata = { title: "Countries", description: "Data center facilities, known and pipeline capacity, operators and cloud regions by country, grouped by world region.", alternates: { canonical: "/countries" }, }; const SORTS = ["name", "facilities", "mw", "pipeline", "cloud", "operators", "per_million", "hyperscale"] as const; type SortKey = (typeof SORTS)[number]; const REGION_ORDER = ["Americas", "Europe", "Asia", "Oceania", "Africa"]; const pipelineMw = (c: CountrySummary): number | null => (c.constructionMw === null && c.plannedMw === null ? null : (c.constructionMw ?? 0) + (c.plannedMw ?? 0)); const perMillion = (c: CountrySummary): number | null => (c.population && c.facilityCount >= 5 ? c.facilityCount / (c.population / 1_000_000) : null); function sorter(s: SortState) { switch (s.key) { case "name": return compareBy((c) => c.name, s.order); case "mw": return compareBy((c) => c.knownMw, s.order); case "pipeline": return compareBy(pipelineMw, s.order); case "cloud": return compareBy((c) => c.cloudRegionCount, s.order); case "operators": return compareBy((c) => c.operatorCount, s.order); case "per_million": return compareBy(perMillion, s.order); case "hyperscale": return compareBy((c) => c.hyperscaleCount + c.aiCount, s.order); default: return compareBy((c) => c.facilityCount, s.order); } } function CountryTable({ rows, base, sp, sort }: { rows: CountrySummary[]; base: string; sp: SearchParams; sort: SortState }) { const th = (key: SortKey) => sortTh(base, sp, sort, key); return ( {rows.map((c) => { const pipe = pipelineMw(c); const pm = perMillion(c); return ( ); })}
Country Facilities Known MW Pipeline Cloud regions Operators Per million Hyperscale · AI
{c.name}
{c.subregion ?? c.region ?? ""}
{fmtInt(c.facilityCount)} {c.knownMw === null ? ( — ) : ( {fmtMw(c.knownMw)} {fmtPct(c.mwCoverage)} coverage )} {pipe === null ? ( — ) : ( {fmtMw(pipe)} )} {fmtInt(c.cloudRegionCount)} {fmtInt(c.operatorCount)} {pm === null ? — : pm.toFixed(2)} {fmtInt(c.hyperscaleCount)} · {fmtInt(c.aiCount)}
); } export default async function CountriesPage({ searchParams }: { searchParams: Promise }) { const sp = await searchParams; const base = routes.countries(); const region = spGet(sp, "region"); const hasSort = Boolean(spGet(sp, "sort")); const sort = parseSort(sp, SORTS, { key: "facilities", order: "desc" }); const res = await api.countries(); const ok = res.items.length > 0 || (await api.health()).ok; const all = res.items.filter((c) => c.facilityCount > 0 || c.cloudRegionCount > 0); const regions = Array.from(new Set(all.map((c) => c.region).filter((x): x is string => Boolean(x)))).sort((a, b) => { const ia = REGION_ORDER.indexOf(a); const ib = REGION_ORDER.indexOf(b); return (ia === -1 ? 99 : ia) - (ib === -1 ? 99 : ib) || a.localeCompare(b); }); const filtered = (region ? all.filter((c) => c.region === region) : all).sort(sorter(sort)); const totals = filtered.reduce((a, c) => ({ f: a.f + c.facilityCount, cr: a.cr + c.cloudRegionCount, mw: a.mw + (c.knownMw ?? 0), cov: a.cov + (c.knownMw !== null ? 1 : 0) }), { f: 0, cr: 0, mw: 0, cov: 0 }); const chipCls = (active: boolean) => cn("inline-flex h-7 shrink-0 items-center whitespace-nowrap rounded-sm border px-2 text-[12px]", active ? "border-ink bg-ink text-paper" : "border-hair-2 bg-surface text-ink hover:bg-surface-2"); return ( {!ok && } {filtered.length === 0 ? ( ) : hasSort || region ? ( ) : (
{regions.map((rg) => { const rows = filtered.filter((c) => c.region === rg); if (!rows.length) return null; const f = rows.reduce((a, c) => a + c.facilityCount, 0); return (

{rg}

{fmtInt(rows.length)} {pluralize(rows.length, "country", "countries")} · {fmtInt(f)} facilities
); })} {filtered.some((c) => !c.region) && (

Other

!c.region)} base={base} sp={sp} sort={sort} />
)}
)}

Per-million uses the latest World Bank population vintage and requires at least 5 facilities. Known MW = IT capacity, or total power when only that is published, over operational facilities. See the{" "} methodology .

); }