npm.io
3.2.0 β€’ Published 4d ago

country-codes-list

Licence
MIT
Version
3.2.0
Deps
0
Size
407 kB
Vulns
0
Weekly
0
Stars
114

country-codes-list

A list of 250 countries with ISO codes, currencies, languages, phone codes and tax identifiers.

npm version CI license npm downloads

Why this package

  • One record per country. It includes data that other packages do not ship together: TIN/VAT identifiers, local-language names, alternative codes (UK, EL) and national phone number lengths.
  • Zero runtime dependencies.
  • TypeScript types for every record and every function.
  • A test suite that checks dataset-wide invariants (unique codes, valid ISO 4217, ITU-T E.164 limits).
  • The same data as JSON and CSV files, on npm and on a CDN.

Install

npm install country-codes-list

The package is CommonJS with named exports. import works through Node's CommonJS interop. There is no native ESM build.

const countryCodes = require("country-codes-list");
// or
import * as countryCodes from "country-codes-list";
import { findOneByCode } from "country-codes-list";

Quick start

Look up a country by any code:

const countryCodes = require("country-codes-list");

countryCodes.findOneByCode("UK").countryCode; // 'GB'
countryCodes.findOneByCode("840").countryNameEn; // 'United States of America'

Build the options of a <select> element:

countryCodes.customArray(
  { name: "{countryNameEn}", value: "{countryCode}" },
  { sortBy: "name" }
);
// [{ name: 'Afghanistan', value: 'AF' }, { name: 'Γ…land Islands', value: 'AX' }, ...]

Group countries by calling code:

countryCodes.customGroupedList("countryCallingCode", "{countryCode}")["1"];
// ['AG', 'AI', 'AS', 'BB', 'BM', 'CA', 'DM', 'GD', 'GU', 'JM', 'KN', 'LC',
//  'MS', 'PR', 'SX', 'TT', 'US', 'VC', 'VG', 'VI', 'DO', 'BS', 'KY', 'MP',
//  'TC', 'UM']

Data fields

Each record is a CountryData object. The example column shows the US record.

Field Type Example Notes and source
countryNameEn string "United States of America" English name.
countryNameLocal string "United States of America" Name in the local language.
countryCode string "US" ISO 3166-1 alpha-2. Unique.
countryCodeAlpha3 string "USA" ISO 3166-1 alpha-3. Unique.
countryCodeNumeric string "840" ISO 3166-1 numeric, three digits with leading zeros ("004" for AF). Empty only for XK (Kosovo).
altCodes string[] (optional) absent Other 2-letter codes in use. Only GB (["UK"]) and GR (["EL"]) have it. Use findOneByCode to search it.
currencyCode string "USD" ISO 4217 code. Empty for AQ (Antarctica).
currencyNameEn string "United States dollar" ISO 4217 English name. Empty for AQ.
currencyNumeric string "840" ISO 4217 numeric, three digits. Empty for AQ. Source: ISO 4217 List One.
currencyDecimals number | null 2 ISO 4217 minor units: 0 for JPY, 3 for BHD. null for AQ. Same source.
currencySymbol string "$" CLDR English narrow symbol from Node's ICU. Not unique. Falls back to the code ("CHF"). Empty for AQ.
tinType string "EIN" Short name of the tax identifier. Populated for 62 of 250 records. Source: Wikipedia.
tinName string "Tax Identification Number" Full name of the tax identifier. Populated for 64 of 250 records. Same source.
officialLanguageCode string "en" ISO 639-1 code of the first official language. ISO 639-3 when the language has no 639-1 code. Source: OSM Nominatim.
officialLanguageNameEn string "English" English name of that language.
officialLanguageNameLocal string "English" Name of that language in the language itself.
countryCallingCode string "1" ITU-T E.164 country code, 1 to 3 digits, no +. Source: Wikipedia.
areaCodes string[] [] National area codes after the calling code. Populated for NANP members (not US or UM), plus CC, CX and SJ. An empty array means "not recorded".
nationalNumberLengths number[] [10] Possible digit counts of the national number, sorted. Empty for AQ, BV, GS, HM, PN, TF, UM. Source: libphonenumber (fixed-line and mobile only).
region string "North America" One of six values adapted from the ITU regions.
flag string "πŸ‡ΊπŸ‡Έ" Flag emoji, derived from countryCode.

Things to know

nationalNumberLengths is a set, not a range. Numbering plans have holes. The Netherlands is [9, 11], so a 10-digit Dutch number is not valid. Use includes, never a min/max comparison.

const nl = countryCodes.findOneByCode("NL").nationalNumberLengths; // [9, 11]
nl.includes(10); // false, correct
10 >= Math.min(...nl) && 10 <= Math.max(...nl); // true, wrong

The area code is counted, the trunk prefix is not. The British number 020 7946 0958 has a national number of 2079460958. That is 10 digits, area code included. Remove the leading 0 before you compare.

countryCodes.findOneByCode("GB").nationalNumberLengths.includes("2079460958".length); // true

currencySymbol is not unique. 29 currencies show "$" (USD, CAD, AUD, MXN and more). "Β£", "kr", "Β₯" and "β‚©" are also shared. Do not use the symbol as a key.

customList keys must be unique. countryCode and countryCodeAlpha3 are unique. countryCallingCode, currencyCode, region and officialLanguageCode are not. With a shared key, only the last country survives. Use customGroupedList for shared keys.

Array fields are not keys or placeholders. altCodes, areaCodes and nationalNumberLengths are arrays. filter, findOne, customList, customGroupedList and sortDataBy reject them (a TypeScript error). A placeholder such as {areaCodes} stays in the output as written.

all() returns a new array on each call. all() === all() is false. You can sort or change the returned array without effect on the dataset. The country objects inside are shared. Treat them as read-only.

Dataset order is not alphabetical. Most records are sorted by countryCode. 33 records (SZ, MK, PH, NL, AE, ..., XK) come at the end, and KI, KN come after KR. If you need a specific order, sort the result.

findOneByCode validates before it uppercases. Input must be 2 or 3 ASCII letters, or 3 ASCII digits, after trim. All other input returns undefined. Unicode case mapping ("ß" to "SS") cannot make a valid code from invalid input.

UK and EL are not ISO codes. findOneByCode("UK") returns the United Kingdom, but countryCode stays "GB". findOne("countryCode", "UK") returns undefined.

region has six values. Africa, Arab States, Asia & Pacific, Europe, North America and South/Latin America. They follow the ITU classification, with two changes: ITU's "The Americas" is split in two, and ITU's "CIS" countries are placed in Europe or Asia & Pacific.

API reference

All examples use const countryCodes = require("country-codes-list");.

all()
all(): CountryData[]

Returns every country in dataset order, as a new array.

countryCodes.all().length; // 250
countryCodes.all()[0].countryNameEn; // 'Andorra'
filter(key, value)
filter(key: CountryScalarProperty, value: string): CountryData[]

Returns every country where key equals value exactly.

countryCodes.filter("currencyCode", "XCG").map((c) => c.countryCode);
// ['CW', 'SX']
findOne(key, value)
findOne(key: CountryScalarProperty, value: string): CountryData | undefined

Returns the first country where key equals value exactly. The comparison is case-sensitive and ignores altCodes.

countryCodes.findOne("countryCodeAlpha3", "ARG").countryNameEn; // 'Argentina'
countryCodes.findOne("countryCode", "ZZ"); // undefined
findOneByCode(code)
findOneByCode(code: string): CountryData | undefined

Resolves an alpha-2, alpha-3, alternative or numeric code to a country. The match is case-insensitive and ignores surrounding spaces. Official codes win over alternative codes. Use it for codes from a browser locale, a VAT number or an external API.

countryCodes.findOneByCode("UK").countryCode; // 'GB'
countryCodes.findOneByCode("gbr").countryCode; // 'GB'
countryCodes.findOneByCode("EL").countryCode; // 'GR'
countryCodes.findOneByCode("004").countryCode; // 'AF'
countryCodes.findOneByCode("4"); // undefined, numeric codes need three digits
countryCodes.findOneByCode("ZZ"); // undefined
customList(key?, label?, options?)
customList(
  key?: CountryScalarProperty,   // default "countryCode"
  label?: string,                // default "{countryNameEn} ({countryCode})"
  options?: { filter?: (country: CountryData) => boolean }
): Record<string, string>

Returns an object with one entry per country. key selects the property that becomes the object key. label is a template. Each {placeholder} is replaced with the value of that property. Unknown placeholders and array fields stay as written.

countryCodes.customList("countryCode", "[{countryCode}] {countryNameEn}: +{countryCallingCode}");
// {
//   AD: '[AD] Andorra: +376',
//   AF: '[AF] Afghanistan: +93',
//   AG: '[AG] Antigua and Barbuda: +1',
//   ...
// }
customGroupedList(key?, label?, options?)
customGroupedList(
  key?: CountryScalarProperty,   // default "countryCallingCode"
  label?: string,                // default "{countryNameEn} ({countryCode})"
  options?: { filter?: (country: CountryData) => boolean }
): Partial<Record<string, string[]>>

Same as customList, but each key maps to an array of all matching countries. Groups keep dataset order. A key that no country matched is absent, so the type is Partial.

countryCodes.customGroupedList("region", "{countryNameEn}", {
  filter: (country) => country.currencyCode === "EUR",
});
// { Europe: ['Andorra', 'Austria', 'Γ…land Islands', 'Belgium', ...], 'South/Latin America': [...], ... }

const onlyAR = countryCodes.customGroupedList("region", "{countryCode}", {
  filter: (country) => country.countryCode === "AR",
});
onlyAR["Europe"]; // undefined
onlyAR["Europe"]?.length ?? 0; // 0
customArray(fields?, options?)
customArray<F extends Record<string, string>>(
  fields?: F,   // default { name: "{countryNameEn} ({countryCode})", value: "{countryCode}" }
  options?: {
    sortBy?: keyof F;                             // a key of YOUR template
    sortDataBy?: CountryScalarProperty;           // a dataset property
    filter?: (country: CountryData) => boolean;
  }
): Record<keyof F, string>[]

Returns one object per country, shaped like fields. Each value is a template with {placeholder} syntax.

Option Applies to Effect
filter dataset Keeps only the countries that return true. Runs first.
sortDataBy dataset property ("countryNameEn") Sorts the countries before rendering.
sortBy key of your template ("name") Sorts the output after rendering.

Both sorts use Intl.Collator with accent sensitivity.

countryCodes.customArray(
  { label: "{flag} {countryNameEn}", value: "{countryCode}" },
  { filter: (c) => c.region === "North America", sortBy: "label" }
);
// [
//   { label: 'πŸ‡§πŸ‡² Bermuda', value: 'BM' },
//   { label: 'πŸ‡¨πŸ‡¦ Canada', value: 'CA' },
//   { label: 'πŸ‡΅πŸ‡² Saint Pierre and Miquelon', value: 'PM' },
//   { label: 'πŸ‡ΊπŸ‡Έ United States of America', value: 'US' }
// ]
utils.groupBy(array, key)
utils.groupBy<T>(array: T[], key: keyof T): Record<string, T[]>

Groups any array of objects by one key. customGroupedList uses it internally.

countryCodes.utils.groupBy(countryCodes.all(), "region")["Arab States"].length; // 22
Types
import type { CountryData, CountryProperty, CountryScalarProperty } from "country-codes-list";
Type Meaning
CountryData One record. See Data fields.
CountryProperty Every key of CountryData, arrays and currencyDecimals included.
CountryScalarProperty Only the string-valued keys. filter, findOne, customList, customGroupedList and sortDataBy accept this type.
const key: CountryScalarProperty = "currencyCode";
const pick = (country: CountryData) => country[key];

Data exports

The package also ships the dataset as files, for spreadsheets, Python, SQL or a web page:

File Content
dist/countries.json The array that all() returns, pretty-printed.
dist/countries.csv One row per country. The header lists every field.

Both files are on jsDelivr, pinned to the major version:

https://cdn.jsdelivr.net/npm/country-codes-list@3/dist/countries.json
https://cdn.jsdelivr.net/npm/country-codes-list@3/dist/countries.csv
const countries = await fetch(
  "https://cdn.jsdelivr.net/npm/country-codes-list@3/dist/countries.json"
).then((r) => r.json());

CSV format notes:

  • UTF-8 without a BOM. Import the file as UTF-8.
  • Rows end with LF. Cells are quoted per RFC 4180.
  • Array fields (altCodes, areaCodes, nationalNumberLengths) are joined with |. null is an empty cell.
  • countryCodeNumeric and currencyNumeric keep their leading zeros. Read these columns as text, or "004" becomes 4.

Contributing

Build and test:

npm ci
npm run build   # tsc, then writes dist/countries.json and dist/countries.csv
npm test        # jest, 8 suites

CI runs the same steps on Node 22 and 24. Write PR titles and bodies in English.

Generated fields

Five fields are written by scripts, not by hand. Do not edit them manually. The currency and number-length scripts need network access. No script runs in CI.

Command Fields Source
npm run data:numeric countryCodeNumeric ISO 3166-1 table embedded in the script.
npm run data:currencies currencyNumeric, currencyDecimals, currencySymbol ISO 4217 List One XML (SIX Group) and Node's ICU.
npm run data:number-lengths nationalNumberLengths libphonenumber PhoneNumberMetadata.xml, pinned to a tag.
npm run data:all All of the above Runs the three scripts in order.

Each script replaces only its own field in src/countriesData.ts. A second run makes no change. Add --check for a dry run that exits with code 1 on drift.

Invariant tests and the known-gaps ledger

tests/dataset-invariants.test.ts asserts rules for every record: unique codes, valid ISO 4217, valid ISO 639, E.164 limits, the six regions. Some rules have known exceptions. Each exception is listed in a KNOWN_GAPS_* constant with a reason.

The test asserts that the ledger is exactly the set of violators. If you fix a data gap, remove its ledger entry in the same PR. If you do not, the test fails.

Migration

v2.x to v3.0
Change Before (v2) After (v3)
countryCallingCode holds the E.164 code only. JM was '876'. JM is '1', and areaCodes is ['876', '658'].
areaCodes is a required string[]. Optional any[]. Always present. Empty means "not recorded".
Key parameters accept CountryScalarProperty only. customList("altCodes", ...) compiled. TypeScript error. Use findOneByCode("UK") for alternative codes.

To dial a full number, join the calling code and an area code: `+${cc}${areaCodes[0]}`.

v1.x to v2.0
Change Before (v1) After (v2)
CountryProperty is a type, not an enum. CountryProperty.countryCode "countryCode", with import type.
Named CommonJS exports. require("country-codes-list") Same, or import * as countryCodes through interop.
Property keys are type-checked. filter("invalidKey", "x") compiled. TypeScript error.

Keywords