Countries

Typed ISO country, language, currency, and continent data with zero-dependency lookup utilities for JavaScript and TypeScript.

Library
npm
v3.4.1
1,326stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
75/100Good
Development Activity76
Maintenance64
Community72
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
81/100Excellent
Architecture82
Code Quality88
Innovation62
Learning Curve90

countries-list packages the ISO 3166-1 country list, ISO 4217 currencies, and ISO 639-1 languages into strongly-typed TypeScript objects that ship as a small, dependency-free module. Each country entry links its continent, capital, calling code, spoken languages, and currency codes, while a companion currencies export (opt-in via a countries-list/currencies subpath) carries full ISO 4217 metadata — English and native currency names, CLDR symbols, numeric codes, and decimal precision — without inflating the size of the main bundle.

Beyond the raw data, the package exposes a handful of pure utility functions: getCountryData and getCountryDataList normalize country records with their ISO2/ISO3 codes attached, getCountryCode reverse-looks-up a country from its English or native name (including historical aliases like ‘Czech Republic’ for Czechia), getCurrency/getCurrencyByNumeric resolve currency metadata by ISO code or numeric code, and getEmojiFlag derives a Unicode flag emoji from a two-letter country code. The library builds to ESM, CommonJS, and an IIFE global from a Bun workspace monorepo, and also publishes minimal JSON maps and a Composer/PHP port for non-JS consumers.

What You Get

  • Typed reference data - continents, countries, languages, and ISO 4217 currencies exported as fully-typed const objects with matching TypeScript types.
  • Reverse-lookup utilities - getCountryCode, getCountryData, getCurrency, and getCurrencyByNumeric resolve between names, ISO2/ISO3 codes, and numeric codes.
  • Emoji flag generation - getEmojiFlag converts a two-letter country code into its Unicode regional-indicator flag emoji.
  • Multiple build targets - ESM, CommonJS, and IIFE bundles from tsup, plus minimal pre-built JSON maps for size-sensitive imports.
  • Non-JS ports - a Composer/Packagist package (annexare/countries-list) mirrors the same dataset for PHP projects.

Common Use Cases

  • Address and signup forms - populate country, phone-code, and currency dropdowns with correctly localized names without maintaining your own ISO lists.
  • Currency-aware checkout flows - look up a currency’s symbol, decimal precision, and numeric code from an ISO 4217 code to format prices correctly per market.
  • Internationalization tooling - resolve a user-entered country name (in English or the native language) back to its ISO2 code for locale detection or analytics normalization.
  • Country picker UI - render a flag emoji next to country names in select menus or user profile displays using getEmojiFlag.

Under The Hood

Architecture The repository is a Bun workspace monorepo (packages/*) that separates the published library (packages/countries, publishing as countries-list) from a data-generation package (packages/scripts) and three isolated test packages (test-js, test-node, test-php). The library itself is data-first: src/data/*.ts holds the raw typed constants (continents.ts, countries.ts, currencies.ts, languages.ts, plus generated countries.2to3.ts/countries.3to2.ts code-mapping tables), and a thin layer of pure functions (getCountryData.ts, getCountryCode.ts, getCurrency.ts, getEmojiFlag.ts) sits on top, each importing only the data module it needs. src/index.ts re-exports the main surface, while src/currencies.ts is a separate entry point so the larger ISO 4217 dataset can be tree-shaken out unless explicitly imported. There is no runtime state or I/O anywhere in the library — every function is a deterministic transform over the bundled constants, so the only thing that could break a consumer is a change to the shape of the generated data files.

Tech Stack The library is authored in TypeScript targeting ESNext and built with tsup (esbuild under the hood) into three formats: ESM (dist/mjs), CommonJS (dist/cjs), and an IIFE global (Countries) for script-tag usage, configured via a shared tsup.config.ts at the package root. The workspace uses Bun as both package manager and task runner (bunfig.toml, bun.lock), Biome for linting/formatting in place of ESLint/Prettier, and tsconfig composite project references shared across sibling packages. A parallel composer.json and packages/test-php package publish and test a PHP-native mirror of the same dataset via Packagist, and packages/scripts regenerates the currencies dataset from the official ISO 4217 list and Unicode CLDR data on demand.

Code Quality Testing is extensive and split by consumer environment: packages/test-js runs Bun’s built-in test runner against the ESM source directly (covering getCountryCode, getCountryData, getCurrency, getEmojiFlag, aliasing behavior, and the built dist currencies output), packages/test-node exercises the CommonJS build under Node, and packages/test-php covers the Composer port — three separate CI workflows (build-test.yml, phpunit.yml, publish-npm.yml) run these independently. Types are strict and exhaustive: every data constant has a matching TCountryCode/TCurrencyCode/TLanguageCode derived via keyof typeof, so consumers get compile-time autocomplete and invalid-code errors. Utility functions favor explicit, defensive logic over shortcuts — getCurrencyByNumeric builds a null-prototype lookup index to avoid prototype-pollution footguns from arbitrary numeric input, and getCountryCode escapes regex metacharacters before building its case-insensitive name matcher. Biome enforces consistent formatting and lint rules across the whole workspace, and Husky/lefthook wire pre-commit checks.

What Makes It Unique Unlike most country-data packages that ship a single flat JSON blob, countries-list treats each dataset (continents, countries, currencies, languages) as an independently typed, independently importable module, so a consumer pulling in just getEmojiFlag does not pay for the ISO 4217 currency table’s bundle weight — that data lives behind an opt-in countries-list/currencies subpath. Its currency model also goes further than most peers by tracking withdrawn-but-still-referenced ISO 4217 codes (e.g. legacy currencies still cited by country records) and by resolving both alpha and zero-padded numeric currency codes, with explicit precedence rules so an active code always wins over a withdrawn one sharing the same numeric identifier. Maintaining a genuinely parallel PHP/Composer distribution from the same source data, validated by its own test suite and CI workflow, is uncommon for a package in this space.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search