import type { Metadata } from "next"; import Link from "next/link"; import { ExtLink } from "@/components/entity/kv"; import { Button } from "@/components/ui/button"; import { Page, PageHeader } from "@/components/ui/card"; import { CountryFlag } from "@/components/ui/country-flag"; import { FilterChips, type Chip } from "@/components/ui/filter-chips"; import { Pagination } from "@/components/ui/pagination"; 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 { countryName, fmtInt } from "@/lib/format"; import { routes } from "@/lib/routes"; import { pageMetadata } from "@/lib/seo"; import { hrefWith, spGet, spInt, type SearchParams } from "@/lib/sort"; export const revalidate = 120; export const metadata: Metadata = pageMetadata({ title: "Internet exchanges", description: "Internet exchange points (IXPs) with connected networks and the data centers where they are present.", path: routes.ixps(), }); const BASE = routes.ixps(); const PER_PAGE = 100; const input = "h-9 rounded-sm border border-hair-2 bg-surface px-2 text-[13px] text-ink placeholder:text-ink-4 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent"; export default async function IxpsPage({ searchParams }: { searchParams: Promise }) { const sp = await searchParams; const q = spGet(sp, "q"); const country = spGet(sp, "country")?.toUpperCase(); const page = spInt(sp, "page", 1); const [res, dash, countries] = await Promise.all([api.ixps({ q, country, page, per_page: PER_PAGE }), api.dashboard(), api.countries()]); const ok = res.total > 0 || res.items.length > 0 || (!q && !country && dash.ok); const total = res.total; const statIxps = dash.ok ? dash.data.stats.ixps : null; const countryOptions = countries.items.filter((c) => c.facilityCount > 0).sort((a, b) => a.name.localeCompare(b.name)); const chips: Chip[] = []; if (q) chips.push({ key: "q", label: "Search", value: q, removeHref: hrefWith(BASE, sp, { q: undefined }) }); if (country) chips.push({ key: "country", label: "Country", value: countryName(country), removeHref: hrefWith(BASE, sp, { country: undefined }) }); return ( 0 ? `${fmtInt(total)} internet exchange points indexed with their connected networks and the facilities where they are present.` : "Internet exchange points (IXPs), the networks they connect and the data centers where they are present."} aside={ } /> {!ok && }
{res.items.length === 0 ? ( q || country ? ( ) : ( PeeringDB IXP data is being ingested; facilities' IXP presence appears on facility pages as soon as it is observed. {statIxps !== null && statIxps > 0 && <> The index currently counts {fmtInt(statIxps)} exchanges.} } action={ Browse data centers } /> ) ) : ( <> {res.items.map((x) => ( ))}
Exchange City Country Networks Facilities Website
{x.name} {x.nameLong && x.nameLong !== x.name &&
{x.nameLong}
} {x.city &&
{x.city}
}
{x.city ?? "—"} {x.networkCount === null ? — : fmtInt(x.networkCount)} {fmtInt(x.facilityCount)} {x.website ? : —}
hrefWith(BASE, sp, { page: p > 1 ? p : undefined })} label="exchanges" className="mt-3" /> )}

Exchange and network data: PeeringDB (attribution requested) and exchange operators. Network counts are as published by the source at the last observation.

); }