These five npm packages provide country-related data for JavaScript applications, but they serve different purposes and follow different standards. countries-list offers a lightweight collection of country information with ISO codes. country-data provides comprehensive country data including currencies, languages, and flags but is no longer actively maintained. country-list is a minimal package focusing on country name-to-code mappings. i18n-iso-countries specializes in ISO 3166-1 country code translations across multiple languages. iso-3166-1 provides strict adherence to the official ISO 3166-1 standard with alpha-2, alpha-3, and numeric codes. Choosing the right package depends on whether you need translations, comprehensive data, minimal footprint, or strict standards compliance.
When building international applications, you'll inevitably need to work with country data β whether for address forms, shipping calculators, analytics dashboards, or user localization. The five packages we're comparing (countries-list, country-data, country-list, i18n-iso-countries, iso-3166-1) all solve this problem, but they take very different approaches. Let's examine how they work under the hood and when each makes sense.
The shape of returned data varies significantly between packages, which affects how you integrate them into your components.
countries-list returns rich country objects with multiple properties.
import { countries } from 'countries-list';
console.log(countries.US);
// { name: 'United States', alpha2: 'US', alpha3: 'USA',
// currency: ['USD'], languages: ['en'], region: 'Americas' }
country-data provides even more detailed objects including flags and calling codes.
import countries from 'country-data';
console.log(countries.countries.US);
// { name: 'United States', alpha2: 'US', alpha3: 'USA',
// currencyCode: 'USD', callingCode: '+1', flag: 'πΊπΈ' }
country-list gives you the simplest structure β just code-to-name mappings.
import countries from 'country-list';
console.log(countries.getCode('United States'));
// 'US'
console.log(countries.getName('US'));
// 'United States'
i18n-iso-countries focuses on translations, returning localized names.
import countries from 'i18n-iso-countries';
import en from 'i18n-iso-countries/langs/en.json';
countries.registerLocale(en);
console.log(countries.getName('US', 'en'));
// 'United States'
console.log(countries.getNames('en'));
// { US: 'United States', CA: 'Canada', ... }
iso-3166-1 provides strict ISO standard objects with all three code types.
import { alpha2, alpha3, numeric } from 'iso-3166-1';
console.log(alpha2.code('US'));
// { name: 'United States', alpha2: 'US', alpha3: 'USA', numeric: '840' }
console.log(alpha3.code('USA'));
// { name: 'United States', alpha2: 'US', alpha3: 'USA', numeric: '840' }
This is where the packages diverge most significantly. If your app serves users in multiple languages, this factor often decides everything.
countries-list includes language codes but not translated country names.
import { countries } from 'countries-list';
// You get the languages spoken IN each country
console.log(countries.FR.languages);
// ['fr']
// But country names are always in English
console.log(countries.FR.name);
// 'France' (not 'France' in French, just English)
country-data similarly provides language codes without translations.
import countries from 'country-data';
console.log(countries.countries.FR.languages);
// ['fr']
console.log(countries.countries.FR.name);
// 'France' (English only)
country-list has no internationalization features at all.
import countries from 'country-list';
// Names are English-only, no locale support
console.log(countries.getName('DE'));
// 'Germany' (cannot get 'Deutschland')
i18n-iso-countries is built specifically for translations with 100+ language packs.
import countries from 'i18n-iso-countries';
import en from 'i18n-iso-countries/langs/en.json';
import de from 'i18n-iso-countries/langs/de.json';
import ja from 'i18n-iso-countries/langs/ja.json';
countries.registerLocale(en);
countries.registerLocale(de);
countries.registerLocale(ja);
console.log(countries.getName('DE', 'en'));
// 'Germany'
console.log(countries.getName('DE', 'de'));
// 'Deutschland'
console.log(countries.getName('DE', 'ja'));
// 'γγ€γ'
iso-3166-1 focuses on codes, not translations.
import { alpha2 } from 'iso-3166-1';
// Names are in English only
console.log(alpha2.code('DE').name);
// 'Germany'
// No locale parameter available
The API patterns affect how easily you can integrate these into your components and utilities.
countries-list uses direct object access β simple and fast.
import { countries } from 'countries-list';
// Direct property access
const country = countries['US'];
const name = country.name;
// Iterate over all countries
Object.values(countries).forEach(country => {
console.log(country.name);
});
country-data uses a nested namespace pattern.
import countries from 'country-data';
// Access through countries.countries namespace
const country = countries.countries['US'];
// Also provides currencies and languages separately
const currency = countries.currencies.USD;
const language = countries.languages.en;
country-list uses function-based lookups.
import countries from 'country-list';
// Bidirectional lookup functions
const code = countries.getCode('United States');
const name = countries.getName('US');
// Get all as array or object
const allCountries = countries.getData(); // array
const allCodes = countries.getCodes(); // array of codes
i18n-iso-countries requires locale registration before use.
import countries from 'i18n-iso-countries';
import en from 'i18n-iso-countries/langs/en.json';
// Must register locales first
countries.registerLocale(en);
// Then use lookup functions
const name = countries.getName('US', 'en');
const code = countries.getCode('United States', 'en');
const allNames = countries.getNames('en');
iso-3166-1 separates lookups by code type.
import { alpha2, alpha3, numeric } from 'iso-3166-1';
// Different functions for different code types
const byAlpha2 = alpha2.code('US');
const byAlpha3 = alpha3.code('USA');
const byNumeric = numeric.code('840');
// All return the same complete object
console.log(byAlpha2.alpha3 === byAlpha3.alpha3);
// true
This factor alone should eliminate some options for new projects.
countries-list is actively maintained with regular updates to reflect ISO changes.
// Current API remains stable
import { countries } from 'countries-list';
// No deprecation warnings, safe for production
country-data is no longer maintained and should not be used in new projects.
import countries from 'country-data';
// β οΈ Package shows deprecation notices on npm
// Last significant update was years ago
// May contain outdated country information
// Recommendation: Migrate to countries-list or i18n-iso-countries
country-list receives occasional maintenance but has a minimal feature set.
import countries from 'country-list';
// Stable but limited β no new features expected
// Fine for simple use cases that won't need expansion
i18n-iso-countries is actively maintained with language pack updates.
import countries from 'i18n-iso-countries';
// Regular updates for new language packs
// ISO standard changes are incorporated
// Safe for production internationalization
iso-3166-1 follows official ISO standard updates.
import { alpha2 } from 'iso-3166-1';
// Updates when ISO 3166-1 standard changes
// More conservative update cycle
// Best for compliance-focused applications
You need country dropdowns with localized names based on user language.
// β
Best: i18n-iso-countries
import countries from 'i18n-iso-countries';
import { useLocale } from './hooks';
function CountrySelect() {
const locale = useLocale();
const countryList = Object.entries(countries.getNames(locale))
.map(([code, name]) => ({ code, name }));
return (
<select>
{countryList.map(c => (
<option key={c.code} value={c.code}>{c.name}</option>
))}
</select>
);
}
// β Avoid: country-list (no translations)
import countries from 'country-list';
// All users see English names regardless of locale
// β Avoid: country-data (deprecated)
import countries from 'country-data';
// May have outdated country information
You need to validate country codes and display full country information.
// β
Good: countries-list
import { countries } from 'countries-list';
function validateCountry(code) {
const country = countries[code];
if (!country) return { valid: false };
return {
valid: true,
name: country.name,
currency: country.currency,
region: country.region
};
}
// β
Also Good: iso-3166-1
import { alpha2 } from 'iso-3166-1';
function validateCountry(code) {
const country = alpha2.code(code);
if (!country) return { valid: false };
return {
valid: true,
name: country.name,
alpha3: country.alpha3,
numeric: country.numeric
};
}
You need country codes with emoji flags for visualization.
// β οΈ Limited: countries-list (no built-in flags)
import { countries } from 'countries-list';
// You'd need to add flag emoji mapping separately
const getFlag = (code) => {
const codePoints = code
.split('')
.map(char => 127397 + char.charCodeAt());
return String.fromCodePoint(...codePoints);
};
// β
Had flags: country-data (but deprecated)
import countries from 'country-data';
const flag = countries.countries['US'].flag;
// πΊπΈ β but package is no longer maintained
// β
Alternative: Build flag utility with any package
import { countries } from 'countries-list';
function CountryWithFlag({ code }) {
const country = countries[code];
const flag = String.fromCodePoint(
...code.split('').map(c => 127397 + c.charCodeAt())
);
return <span>{flag} {country.name}</span>;
}
You need strict ISO 3166-1 compliance for regulatory reporting.
// β
Best: iso-3166-1
import { alpha2, alpha3, numeric } from 'iso-3166-1';
function generateComplianceReport(countryCode) {
const country = alpha2.code(countryCode);
return {
iso_alpha2: country.alpha2,
iso_alpha3: country.alpha3,
iso_numeric: country.numeric,
// All three code types for regulatory requirements
};
}
// β οΈ Acceptable: countries-list
import { countries } from 'countries-list';
// Has alpha2 and alpha3 but not numeric codes
const country = countries['US'];
// Missing numeric code may cause compliance issues
| Feature | countries-list | country-data | country-list | i18n-iso-countries | iso-3166-1 |
|---|---|---|---|---|---|
| ISO Alpha-2 | β | β | β | β | β |
| ISO Alpha-3 | β | β | β | β | β |
| ISO Numeric | β | β | β | β | β |
| Translations | β | β | β | β (100+) | β |
| Currency Data | β | β | β | β | β |
| Language Codes | β | β | β | β | β |
| Flag Emoji | β | β | β | β | β |
| Calling Codes | β | β | β | β | β |
| Active Maintenance | β | β | β οΈ | β | β |
| Bundle Impact | Low | Medium | Minimal | Medium (per locale) | Low |
If your app only serves one language, keep things simple.
// Recommended: countries-list
import { countries } from 'countries-list';
// Rich data without i18n complexity
const countryData = Object.values(countries).map(c => ({
code: c.alpha2,
name: c.name,
currency: c.currency[0]
}));
Internationalization should drive your choice.
// Recommended: i18n-iso-countries
import countries from 'i18n-iso-countries';
// Register locales at app initialization
function initI18n() {
const locales = ['en', 'de', 'fr', 'es', 'ja'];
locales.forEach(locale => {
const lang = require(`i18n-iso-countries/langs/${locale}.json`);
countries.registerLocale(lang);
});
}
// Use in components with user's locale
function getCountryName(code, userLocale) {
return countries.getName(code, userLocale) || countries.getName(code, 'en');
}
When regulations require specific ISO standards.
// Recommended: iso-3166-1
import { alpha2, alpha3, numeric } from 'iso-3166-1';
// Always validate against official ISO codes
function validateISOCode(code, type = 'alpha2') {
const validator = { alpha2, alpha3, numeric }[type];
return validator.code(code) !== undefined;
}
If you're currently using the deprecated country-data, here's how to migrate.
// Before (country-data - deprecated)
import countries from 'country-data';
const name = countries.countries['US'].name;
const flag = countries.countries['US'].flag;
// After (countries-list)
import { countries } from 'countries-list';
const name = countries['US'].name;
// For flags, use emoji conversion utility
const flag = String.fromCodePoint(
...'US'.split('').map(c => 127397 + c.charCodeAt())
);
// After (i18n-iso-countries - if you need translations)
import countries from 'i18n-iso-countries';
import en from 'i18n-iso-countries/langs/en.json';
countries.registerLocale(en);
const name = countries.getName('US', 'en');
Choose countries-list when:
Choose i18n-iso-countries when:
Choose iso-3166-1 when:
Choose country-list when:
Avoid country-data when:
countries-list as the direct replacementFor most modern frontend applications, countries-list and i18n-iso-countries cover 90% of use cases. Pick countries-list for data-rich, single-language apps. Pick i18n-iso-countries when translations matter. Reserve iso-3166-1 for compliance scenarios, use country-list for minimal needs, and migrate away from country-data as soon as possible.
Choose countries-list if you need a lightweight, dependency-free package with country names, ISO codes, and basic metadata like currencies and languages. It works well for dropdown menus, form validation, and display purposes where you need more than just codes but don't want heavy dependencies. The API is straightforward and returns plain JavaScript objects.
Avoid country-data for new projects as it is no longer actively maintained. If you're maintaining legacy code that uses it, consider migrating to countries-list or i18n-iso-countries. It once provided comprehensive data including flags and calling codes, but the lack of updates means it may contain outdated information.
Choose country-list if you need the simplest possible solution for mapping country codes to names. It's ideal for basic dropdowns or validation where you only need code-name pairs without additional metadata. The minimal API means less to learn but also less flexibility for complex use cases.
Choose i18n-iso-countries if your application needs country names in multiple languages. It's the best choice for internationalized applications where users see country names in their preferred language. The package supports 100+ languages and provides reliable ISO 3166-1 translations with a clean API for registration and lookup.
Choose iso-3166-1 if you need strict compliance with the official ISO 3166-1 standard and want all three code types (alpha-2, alpha-3, numeric). It's suitable for applications dealing with international standards, compliance requirements, or systems that must exchange data with other ISO-compliant services.
Continents & countries: ISO 3166-1 alpha-2 code (with alpha-2 to alpha-3 set), name, ISO 639-1 languages, capital and ISO 4217 currency codes, native name, calling codes. Lists are available in JSON, CSV and SQL formats. Also, contains separate JSON files with additional country Emoji flags data.
Version 3 comes with some data structure changes. It was completely reworked under the hood with TypeScript, ESM exports and Turborepo file structure.
Everything is strongly typed so you can easily use data with auto-complete in your IDE.
Note: If your projects depend on the old structure, carefully specify required versions in your dependencies.
Package is available via:
bun add countries-listnpm install countries-listcomposer require annexare/countries-listModule exports continents, countries, languages and utility functions.
// Interfaces and types
import type {
ICountry,
ICountryData,
ILanguage,
TContinentCode,
TCountryCode,
TLanguageCode,
} from 'countries-list'
// Main data and utils
import { continents, countries, languages } from 'countries-list'
// Utils
import { getCountryCode, getCountryData, getCountryDataList, getEmojiFlag } from 'countries-list'
// Minimal data in JSON
import countries2to3 from 'countries-list/minimal/countries.2to3.min.json'
import countries3to2 from 'countries-list/minimal/countries.3to2.min.json'
import languageNames from 'countries-list/minimal/languages.native.min'
getCountryCode('Ukraine') // 'UA'
getCountryCode('Π£ΠΊΡΠ°ΡΠ½Π°') // 'UA'
getCountryData('UA') // ICountryData
Built files are in the dist directory of this repository, and packages/countries directory contains source data.
Note: JS build contains ES modules, CommonJS and IIFE (for now)
cjs/index.jsmjs/index.jsindex.iife.jsconst continents = {
AF: 'Africa',
AN: 'Antarctica',
AS: 'Asia',
EU: 'Europe',
NA: 'North America',
OC: 'Oceania',
SA: 'South America',
}
const countries = {
// ...
UA: {
name: 'Ukraine',
native: 'Π£ΠΊΡΠ°ΡΠ½Π°',
phone: [380],
continent: 'EU',
capital: 'Kyiv',
currency: ['UAH'],
languages: ['uk'],
},
// ...
}
const languages = {
// ...
uk: {
name: 'Ukrainian',
native: 'Π£ΠΊΡΠ°ΡΠ½ΡΡΠΊΠ°',
},
ur: {
name: 'Urdu',
native: 'Ψ§Ψ±Ψ―Ω',
rtl: 1,
},
// ...
}
Everything is generated from strongly typed files in packages/countries/src, including SQL file.
Everything in dist is generated,
so please make data related changes ONLY to files from packages/countries, commit them.
Use bun run build (or turbo build, turbo test) command to build/test generated files.
Prepared by Annexare Studio from different public sources. Feel free to use it as you need in your apps or send updates into this public repository. It's under MIT license.