Migrating from RestCountries to countries.dev

A code-first guide to replacing RestCountries v3.1 or v5 with countries.dev — endpoint-by-endpoint mapping, the response shape, and no API key.

Back

Short version: RestCountries v3.1 is deprecated, v5 needs an API key, and you'd like your app working again without signing up for anything. Here's the swap.

Endpoint mapping

countries.dev mirrors the endpoints people actually used. Drop the host and the version segment:

What you wantRestCountriescountries.dev
All countries/v3.1/all/countries
By name/v3.1/name/{name}/name/{name}
By ISO code/v3.1/alpha/{code}/alpha/{code}
By currency/v3.1/currency/{code}/currency/{code}
By language/v3.1/lang/{code}/lang/{code}
By capital/v3.1/capital/{city}/capital/{city}
By region/v3.1/region/{region}/region/{region}

The full list has a few more (subregion, calling code, top-level domain, numeric code).

The actual code change

Before — v5, with the key and header you now need:

const res = await fetch(
  "https://api.restcountries.com/countries/v5/alpha/FR",
  { headers: { Authorization: `Bearer ${process.env.RC_KEY}` } }
);

After:

const res = await fetch("https://countries.dev/alpha/FR");

No env var, no header, no account. That's the migration.

Heads up: the response shape

countries.dev uses a flat shape — the v2-style one a lot of older code already expected — not v3.1's nested objects. So a couple of field reads change:

// RestCountries v3.1
country.name.common   // "France"
country.capital[0]    // "Paris"

// countries.dev
country.name          // "France"
country.capital       // "Paris"

Currencies and languages come back as arrays of objects:

{
  "name": "France",
  "capital": "Paris",
  "currencies": [{ "code": "EUR", "name": "Euro", "symbol": "€" }],
  "languages": [{ "iso639_1": "fr", "iso639_2": "fra", "name": "French" }],
  "flag": "🇫🇷"
}

If you only read a few fields, request them and skip the rest:

curl "https://countries.dev/countries?fields=name,alpha2Code,flag"

You can also sort, limit, and offset any list endpoint — handy now that you're not paginating around a quota.

One thing RestCountries can't do

While you're in here: /ip/{ip} geolocates an address and returns the whole country record, not just a two-letter code.

curl https://countries.dev/ip/8.8.8.8

That's usually what "get the user's country" was really after.

Missing an endpoint you relied on? Let me know and I'll take a look.

Written by

Dov Azencot

At

Mon Jun 22 2026