INTRODUCTION

CityKit is a zero-dependency TypeScript utility library for working with world city data.

What is CityKit

CityKit provides a unified, fast, and dependency-free way to query, filter, and calculate distances between nearly 50,000 cities worldwide. It is designed to be lightweight enough for browser bundles while remaining powerful enough for backend geospatial workflows.

Unlike massive geo-databases, CityKit bundles a heavily optimized, compressed dataset directly into the npm package. This allows synchronous, in-memory lookups with zero network requests or database configuration.

Key Features

  • 15 utility functions — Searching, distances, radiuses, nearest neighbors, and filtering.
  • 49,992 cities — Coverage across 242 countries.
  • TypeScript-first — Comprehensive types for all objects and parameters.
  • ESM + CJS — Supports modern and legacy module systems.
  • Zero dependencies — Keeps your node_modules lean and secure.
  • Browser compatible — Works in Next.js, React, Vue, and vanilla JS.

Data Source

The city data is sourced from the open-source SimpleMaps World Cities Database. It includes latitude, longitude, population estimates, country codes, and administrative divisions.

INSTALLATION

npm install

Bash
npm install @novaedgedigitallabs/citykit

Yarn / pnpm alternatives

Bash
yarn add @novaedgedigitallabs/citykit pnpm add @novaedgedigitallabs/citykit

Import (Full dataset)

For Node.js backends or applications where bundle size is less critical:

TypeScript
import { search, distance } from '@novaedgedigitallabs/citykit'

Import (Lite dataset)

For browser bundles and frontend applications:

TypeScript
import { search } from '@novaedgedigitallabs/citykit/lite'
NOTE

Lite version includes only cities with population ≥ 500,000 (1,422 cities). Ideal for browser bundles and mobile apps. See Full vs Lite for details.

QUICK START

Basic Search

TypeScript
import { search } from '@novaedgedigitallabs/citykit' const cities = search('delhi', { country: 'IN', limit: 1 }) // → [{ city: 'Delhi', country: 'India', population: 32226000, ... }]

Calculating Distance

TypeScript
import { distance } from '@novaedgedigitallabs/citykit' distance('Mumbai', 'Delhi') // → { km: 1153.64, miles: 716.84 }

Finding Nearest City

TypeScript
import { nearest } from '@novaedgedigitallabs/citykit' nearest({ lat: 48.8584, lng: 2.2945 }) // → [{ city: 'Paris', country: 'France', ... }]

Typo-Tolerant Search

TypeScript
import { fuzzySearch } from '@novaedgedigitallabs/citykit' fuzzySearch('bangalor') // → [{ city: 'Bangalore', country: 'India', ... }]

TYPESCRIPT SUPPORT

Core Interfaces

TypeScript
export interface City { city: string; city_ascii: string; lat: number; lng: number; country: string; iso2: string; iso3: string; admin_name: string; capital: 'primary' | 'admin' | 'minor' | null; population: number | null; id: number; } export interface DistanceResult { km: number; miles: number; } export interface CountryInfo { country: string; iso2: string; iso3: string; cities: City[]; } export interface CountryListItem { country: string; iso2: string; iso3: string; count: number; } export interface DatasetStats { totalCities: number; totalCountries: number; totalCapitals: number; largestCity: City | null; smallestCity: City | null; averagePopulation: number; totalPopulation: number; }

Options Interfaces

TypeScript
export interface SearchOptions { limit?: number; country?: string; exact?: boolean; } export interface FuzzySearchOptions { limit?: number; country?: string; threshold?: number; } export interface NearestOptions { limit?: number; country?: string; } export interface WithinRadiusOptions { limit?: number; country?: string; } export interface PopulationOptions { min?: number; max?: number; limit?: number; } export interface RandomOptions { country?: string; continent?: string; minPopulation?: number; }

CITY OBJECT

The City Interface

The City object is the core data structure returned by almost all functions in CityKit.

FieldTypeDescription
citystringNative display name (e.g. "Москва")
city_asciistringASCII-safe name used for search (e.g. "Moskva")
latnumberLatitude in decimal degrees
lngnumberLongitude in decimal degrees
countrystringFull country name
iso2stringISO 3166-1 alpha-2 code (e.g. "IN")
iso3stringISO 3166-1 alpha-3 code (e.g. "IND")
admin_namestringState or province name
capital"primary" | "admin" | "minor" | nullCapital status
populationnumber | nullPopulation (null if unknown)
idnumberUnique city identifier

Example Object

JSON
{ "city": "Tokyo", "city_ascii": "Tokyo", "lat": 35.6897, "lng": 139.6922, "country": "Japan", "iso2": "JP", "iso3": "JPN", "admin_name": "Tōkyō", "capital": "primary", "population": 37785000, "id": 1392685764 }

FULL VS LITE DATASET

Comparison

FullLite
Import@novaedgedigitallabs/citykit@novaedgedigitallabs/citykit/lite
Cities49,9921,422
Countries241141
Size~4.8 MB~137 KB
FilterAll citiesPopulation ≥ 500,000
APIIdenticalIdentical
NOTE

All 15 functions work identically in both versions. The lite version simply operates on a reduced in-memory array.

API REFERENCE

15 utility functions for searching, filtering, and calculating distances.
search()
Substring search with smart ranking.
fuzzySearch()
Typo-tolerant search with Levenshtein.
nearest()
Closest city to any coordinates.
distance()
km & miles between any two cities.
withinRadius()
All cities within X km of a point.
byCountry()
Every city in a country by ISO2.
byContinent()
Filter cities by continent.
byAdmin()
Filter by state or province.
byPopulation()
Filter by population range.
capitals()
National and state capitals.
getCity()
Single city exact lookup.
getByIso2()
Country info and all its cities.
listCountries()
All 242 countries with city counts.
random()
Random city with optional filters.
stats()
Full dataset statistics.
getContinentNames()
List all continent names.

FUZZYSEARCH()

Typo-tolerant search with Levenshtein distance.
fuzzySearch(query: string, options?: FuzzySearchOptions): City[]
ParameterTypeRequiredDescription
querystringrequiredSearch string with possible typos
options.countrystringoptionalISO2 country filter
options.limitnumberoptionalMax results (default: 10)
options.thresholdnumberoptionalMax edit distance (default: 3)
RETURNS
City[] sorted by edit distance ascending, then population descending.

Example

TypeScript
fuzzySearch('bangalor') // → [{ city: 'Bangalore', country: 'India', ... }] fuzzySearch('Nwe Yrok', { limit: 1 }) // → [{ city: 'New York', ... }]

Edge cases

  • Empty query returns [].
  • Threshold controls tolerance — lower threshold means stricter matching.

NEAREST()

Find the closest city to any coordinates.
nearest(coords: { lat: number; lng: number }, options?: NearestOptions): City[]
ParameterTypeRequiredDescription
coords.latnumberrequiredLatitude in decimal degrees
coords.lngnumberrequiredLongitude in decimal degrees
options.limitnumberoptionalNumber of nearest cities to return (default: 1)
options.countrystringoptionalRestrict search to specific country (ISO2)
RETURNS
City[] sorted by distance ascending.

Example

TypeScript
nearest({ lat: 48.8584, lng: 2.2945 }) // → [{ city: 'Paris', country: 'France', ... }] nearest({ lat: 22.7196, lng: 75.8577 }, { limit: 3, country: 'IN' }) // → 3 nearest Indian cities to Indore

Edge cases

  • O(n) complexity — computes haversine distance for all cities.
  • Use the lite version if executing in performance-critical paths on the client side.

DISTANCE()

Calculates the great-circle distance between two cities.
distance(from: string | { lat: number; lng: number }, to: string | { lat: number; lng: number }): DistanceResult | null
ParameterTypeRequiredDescription
fromstring | objectrequiredCity name string or coordinate object
tostring | objectrequiredCity name string or coordinate object
RETURNS
{ km: number, miles: number } | null

Example

TypeScript
distance('Mumbai', 'Delhi') // → { km: 1153.64, miles: 716.84 } distance('Tokyo', { lat: 40.7128, lng: -74.006 }) // → { km: 10846.97, miles: 6739.99 } distance('NonExistent', 'Paris') // → null

Edge cases

  • String names resolve to the highest-population match on collision.
  • Returns null if either city string cannot be found in the dataset.

WITHINRADIUS()

Find all cities within a certain radius of coordinates.
withinRadius(coords: { lat: number; lng: number }, radiusKm: number, options?: WithinRadiusOptions): City[]
ParameterTypeRequiredDescription
coordsobjectrequiredOrigin coordinates {lat, lng}
radiusKmnumberrequiredRadius in kilometers
options.countrystringoptionalISO2 country filter
options.limitnumberoptionalMax results
RETURNS
City[] within radius, sorted by distance ascending.

Example

TypeScript
withinRadius({ lat: 22.7196, lng: 75.8577 }, 100) // → All cities within 100km of Indore withinRadius({ lat: 51.5074, lng: -0.1278 }, 50, { country: 'GB' }) // → UK cities within 50km of London

BYCOUNTRY()

Get all cities for a specific country.
byCountry(iso2: string): City[]
ParameterTypeRequiredDescription
iso2stringrequiredISO 3166-1 alpha-2 country code

Example

TypeScript
byCountry('JP') // → 1,370+ cities in Japan byCountry('in') // → case-insensitive, works

BYCONTINENT()

Filter all cities by continent.
byContinent(continent: string): City[]
ParameterTypeRequiredDescription
continentstringrequiredContinent name string

Valid values: "Africa", "Asia", "Europe", "North America", "South America", "Oceania", "Antarctica"

Example

TypeScript
byContinent('Asia') // → 18,000+ cities byContinent('north america') // → case-insensitive

BYADMIN()

Filter cities by state or province.
byAdmin(adminName: string, iso2?: string): City[]
ParameterTypeRequiredDescription
adminNamestringrequiredState or province name
iso2stringoptionalRestrict to a specific country

Example

TypeScript
byAdmin('Maharashtra', 'IN') // → 201 cities byAdmin('California') // → all California cities

Edge cases

  • The admin_name field uses native characters. Both 'Mahārāshtra' and 'Maharashtra' match due to substring matching.

BYPOPULATION()

Filter and limit cities by population.
byPopulation(options: PopulationOptions): City[]
ParameterTypeRequiredDescription
options.minnumberoptionalMinimum population
options.maxnumberoptionalMaximum population
options.limitnumberoptionalMax results to return

Example

TypeScript
byPopulation({ min: 10000000 }) // → Cities with 10M+ population, sorted desc byPopulation({ min: 1000000, max: 5000000, limit: 10 }) // → Top 10 cities between 1M-5M

Edge cases

  • Cities with null population are excluded.

CAPITALS()

Get all national and state capitals.
capitals(iso2?: string): City[]
ParameterTypeRequiredDescription
iso2stringoptionalRestrict to a specific country

Example

TypeScript
capitals() // → 242 national capitals capitals('IN') // → India's national + state capitals

GETCITY()

Find an exact city match.
getCity(name: string, iso2?: string): City | null
ParameterTypeRequiredDescription
namestringrequiredExact name of the city
iso2stringoptionalRestrict to a specific country to avoid collisions

Example

TypeScript
getCity('Paris') // → Paris, France getCity('Paris', 'US') // → Paris, Texas, United States

GETBYISO2()

Get aggregated country info and all associated cities.
getByIso2(iso2: string): CountryInfo | null
ParameterTypeRequiredDescription
iso2stringrequiredISO 3166-1 alpha-2 code
RETURNS
{ country, iso2, iso3, cities }

Example

TypeScript
getByIso2('DE') // → { country: 'Germany', iso2: 'DE', iso3: 'DEU', cities: [...] }

LISTCOUNTRIES()

List all countries in the dataset with their city counts.
listCountries(): CountryListItem[]
RETURNS
{ country, iso2, iso3, count }[] sorted alphabetically by country name.

Example

TypeScript
listCountries() // → [{ country: 'Afghanistan', iso2: 'AF', iso3: 'AFG', count: 73 }, ...]

RANDOM()

Get a random city, optionally filtered.
random(options?: RandomOptions): City | null
ParameterTypeRequiredDescription
options.countrystringoptionalRestrict to specific country
options.continentstringoptionalRestrict to specific continent
options.minPopulationnumberoptionalMinimum population filter

Example

TypeScript
random() // → any random city random({ country: 'IN' }) // → random Indian city random({ continent: 'Europe', minPopulation: 1000000 }) // → random European city with 1M+ pop

STATS()

Get statistics about the dataset.
stats(): DatasetStats
RETURNS
{ totalCities, totalCountries, totalCapitals, largestCity, smallestCity, averagePopulation, totalPopulation }

Example

TypeScript
stats() // → { // totalCities: 49992, // totalCountries: 241, // largestCity: { city: 'Tokyo', population: 37785000, ... }, // totalPopulation: 5258389250 // }

GETCONTINENTNAMES()

Get a list of all supported continents.
getContinentNames(): string[]
RETURNS
['Africa', 'Asia', 'Europe', 'North America', 'South America', 'Oceania', 'Antarctica']

CHANGELOG

v1.2.0

  • Added: Lite dataset optimized for browser bundles (@novaedgedigitallabs/citykit/lite).
  • Added: withinRadius now supports country filtering.
  • Changed: Improved fuzzy search algorithm performance.

v1.1.1

  • Fixed: Handling of null population when sorting cities.
  • Fixed: Minor typing issues in City interface.

v1.0.1

  • Fixed: Build missing type definitions issue.

v1.0.0

  • Added: Initial release with 15 core utility functions.
  • Added: 49,992 cities across 242 countries.