Official countries, states, and cities database with iOS/Safari support and minimal bundle size.
Environment: π₯οΈ Server-side only (Node.js, Next.js API routes, Express, etc.)
- π Complete Data: 250+ countries, 5,000+ states, 150,000+ cities
- π± iOS Compatible: No stack overflow errors on Safari/iOS browsers
- π Minimal Bundle: <10KB initial load, lazy-load everything else
- π Lazy Loading: Dynamic imports for optimal performance
- π Translations: 18+ languages supported
- β° Timezone Data: Full timezone information per location
- π TypeScript: Full type definitions included
- π§ Tree-Shakeable: Only bundle what you use
The popular country-state-city package (162K weekly downloads) has critical issues:
- π΄ 8MB bundle size (includes ALL data)
- π΄ iOS Safari crashes with stack overflow errors
- π΄ Unmaintained for 2+ years
- π΄ Static imports force entire bundle
This package solves each of those problems:
- β Minimal bundle (<10KB initial)
- β Dynamic imports & lazy loading
- β iOS/Safari compatible
- β Always updated from authoritative database
- β Tree-shakeable & code-splittable
npm install @countrystatecity/countries
# or
yarn add @countrystatecity/countries
# or
pnpm add @countrystatecity/countries
β οΈ Server-Side Only: This package requires Node.js file system access and cannot be used in browser environments. For frontend use, install@countrystatecity/countries-browserinstead β same API, works in React/Vue/Svelte/Vite.
import { getCountries, getStatesOfCountry, getCitiesOfState } from '@countrystatecity/countries';
// Get all countries (lightweight - ~5KB)
const countries = await getCountries();
console.log(countries[0]);
// { id: 1, name: "United States", iso2: "US", emoji: "πΊπΈ", ... }
// Get all states in a country (~10-100KB depending on country)
const states = await getStatesOfCountry('US');
console.log(states[0]);
// { id: 1, name: "California", iso2: "CA", ... }
// Get all cities in a state (~5-200KB depending on state)
const cities = await getCitiesOfState('US', 'CA');
console.log(cities[0]);
// { id: 1, name: "Los Angeles", latitude: "34.05", ... }Get lightweight list of all countries (basic info only).
- Returns:
Promise<ICountry[]> - Bundle Impact: ~5KB
Get full country metadata including timezones and translations.
- Parameters:
countryCode- ISO2 code (e.g., 'US') - Returns:
Promise<ICountryMeta | null> - Bundle Impact: ~5KB per country
Get all states/provinces for a country.
- Parameters:
countryCode- ISO2 code - Returns:
Promise<IState[]> - Bundle Impact: ~10-100KB depending on country
Get specific state details.
- Parameters:
countryCode,stateCode - Returns:
Promise<IState | null>
Get all cities in a specific state.
- Parameters:
countryCode,stateCode - Returns:
Promise<ICity[]> - Bundle Impact: ~5-200KB depending on state
Get ALL cities in an entire country.
- Warning: Large data size, use sparingly
- Returns:
Promise<ICity[]>
Get every city globally.
- Warning: MASSIVE data (8MB+), rarely needed
- Returns:
Promise<ICity[]>
Check if country code exists.
- Returns:
Promise<boolean>
Check if state code exists in a country.
- Returns:
Promise<boolean>
Search cities by partial name match.
- Returns:
Promise<ICity[]>
Get country name from code.
- Returns:
Promise<string | null>
Get state name from code.
- Returns:
Promise<string | null>
Get timezone for specific city.
- Returns:
Promise<string | null>
Get all timezones for a country.
- Returns:
Promise<string[]>
import type { ICountry, ICountryMeta, IState, ICity, ITimezone } from '@countrystatecity/countries';| Action | @countrystatecity/countries | country-state-city |
|---|---|---|
| Install & import | 5KB | 8MB |
| Load countries | +2KB | - |
| Load US states | +30KB | - |
| Load CA cities | +15KB | - |
| Total for typical use | ~50KB | 8MB |
160x smaller bundle size!
# Run all tests
npm test
# Run iOS compatibility tests specifically
npm run test:ios
# Watch mode
npm run test:watchAll packages include comprehensive tests:
- β Unit tests
- β Integration tests
- β iOS/Safari compatibility tests
Every push and PR automatically:
- β Runs type checking
- β Executes comprehensive tests
- β Builds the package
- β Validates bundle sizes
- β Tests iOS/Safari compatibility
Automated publishing to NPM on version changes:
- π Detects version bumps in package.json
- π¦ Builds and tests before publishing
- π Publishes to NPM registry
- π·οΈ Creates GitHub release with changelog
This package and its data are licensed under the Open Database License (ODbL) v1.0. The data is sourced from the Countries States Cities Database which is also licensed under ODbL-1.0.
You are free to share, create, and adapt this database as long as you attribute the original sources, distribute adaptations under the same license, and don't use technical restrictions to lock down the data.
Contributions are welcome! Please open an issue or PR.
For data-related issues (incorrect country names, missing cities, wrong coordinates, etc.), please report them to the Countries States Cities Database repository, which is the source of data for this package.
This package is part of the @countrystatecity package ecosystem:
-
@countrystatecity/countries (This package) β Server-side countries, states, and cities database. Environment: Node.js, Next.js API routes, Express. Bundle: <10KB initial load.
-
@countrystatecity/countries-browser β Browser-native version with jsDelivr CDN and lazy loading. Environment: React, Vue, Svelte, Vite, any browser. Same API as this package β zero config, just import and use.
-
@countrystatecity/timezones β Comprehensive timezone data with conversion utilities. Environment: Server-side only. Bundle: <20KB initial load.
Use this package (@countrystatecity/countries) when:
- β Building API endpoints or backends
- β Using Next.js App Router server components
- β Running in Node.js, serverless functions (Vercel, AWS Lambda)
- β You have file system access
- β Building command-line tools
For browser/frontend use:
Use @countrystatecity/countries-browser β same API, works directly in React, Vue, Svelte, Vite:
npm install @countrystatecity/countries-browserimport { getCountries, getStatesOfCountry, getCitiesOfState } from '@countrystatecity/countries-browser';
const countries = await getCountries();
const states = await getStatesOfCountry('US');
const cities = await getCitiesOfState('US', 'CA');