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
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, create API endpoints using this package and fetch data from your client.
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';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
- β Minimal bundle (<10KB initial)
- β Dynamic imports & lazy loading
- β iOS/Safari compatible
- β Always updated from authoritative database
- β Tree-shakeable & code-splittable
| 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: Credit the original sources
- Share-Alike: Distribute adaptations under the same license
- Keep Open: Don't use technical restrictions
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
-
- 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:
Until the browser package is available, create API endpoints:
// pages/api/countries.ts (Next.js API route)
import { getCountries } from '@countrystatecity/countries';
export default async function handler(req, res) {
const countries = await getCountries();
res.json(countries);
}
// components/CountrySelector.tsx (Frontend)
const countries = await fetch('/api/countries').then(r => r.json());