npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@novaedgedigitallabs/citykit

v1.3.0

Published

World cities search, distance, geo utilities & India-specific tools — 49,992 cities, enriched with timezone, currency, calling code, continent & more

Readme

@novaedgedigitallabs/citykit

World cities search, distance, geo utilities & India-specific tools — 49,992 cities across 242 countries — enriched with timezone, currency, calling code, continent & more.

A zero-dependency utility library for searching cities, calculating distances, finding nearest locations, autocompleting city names, and querying rich country metadata. Ships with a full dataset and a lightweight variant.

npm version License: MIT


Install

npm install @novaedgedigitallabs/citykit

Quick Start

import { search, distance, nearest, autocomplete } from '@novaedgedigitallabs/citykit';

// Search cities
const results = search('london', { limit: 3 });
// → [{ city: "London", country: "United Kingdom", timezone: 0, currency: "GBP", ... }]

// Autocomplete for form inputs
const suggestions = autocomplete('mumb', { country: 'IN', limit: 5 });
// → [{ city: "Mumbai", ... }]

// Distance between two cities
const dist = distance('Mumbai', 'Delhi');
// → { km: 1153.64, miles: 716.84 }

// Nearest city to coordinates
const [city] = nearest({ lat: 28.6139, lng: 77.209 });
// → { city: "New Delhi", country: "India", callingCode: "+91", ... }

What's New in v1.3.0

| Feature | Functions Added | |---|---| | Enriched city fields | isCapital, continent, timezone, currency, callingCode on every City object | | Country metadata | getCountryMeta(), getCountryContinent() | | Geo: bounding box | getBoundingBox() | | Autocomplete | autocomplete() with minChars guard | | India utilities | getIndianCities(), getCitiesByState(), getCityTier(), getIndianStates(), getTierThresholds() |


API Reference

search(query, options?)

Search cities by name. Case-insensitive substring match on city_ascii. Sorted: exact → starts-with → contains.

search(query: string, options?: SearchOptions): City[]

| Option | Type | Default | Description | |---|---|---|---| | country | string | — | Filter by ISO2 code (e.g. "IN") | | limit | number | 10 | Max results | | exact | boolean | false | Exact match only |

search('paris');
// → [{ city: "Paris", country: "France", ... }, ...]

search('delhi', { country: 'IN', limit: 3 });
search('Tokyo', { exact: true });

autocomplete(query, options?) ✨ New

Optimized for form inputs — applies a minChars guard to skip processing on very short queries. Results are prefix-sorted (starts-with first).

autocomplete(query: string, options?: AutocompleteOptions): City[]

| Option | Type | Default | Description | |---|---|---|---| | minChars | number | 1 | Skip query if shorter than this | | country | string | — | Filter by ISO2 code | | limit | number | 10 | Max results |

import { autocomplete } from '@novaedgedigitallabs/citykit';

autocomplete('mum', { country: 'IN', limit: 5 });
// → [{ city: "Mumbai", ... }, { city: "Mumbra", ... }]

autocomplete('M', { minChars: 2 });
// → []  (query too short, returns immediately)

fuzzySearch(query, options?)

Fuzzy search using Levenshtein distance — handles typos. Sorted by edit distance, then population descending.

fuzzySearch(query: string, options?: FuzzySearchOptions): City[]

| Option | Type | Default | Description | |---|---|---|---| | country | string | — | Filter by ISO2 code | | limit | number | 10 | Max results | | threshold | number | 3 | Max Levenshtein distance |

import { fuzzySearch } from '@novaedgedigitallabs/citykit';

fuzzySearch('bangalor');
// → [{ city: "Bangalore", city_ascii: "Bangalore", ... }]

nearest(coords, options?)

Find the nearest city/cities to coordinates using the Haversine formula.

nearest(coords: { lat: number; lng: number }, options?: NearestOptions): City[]

| Option | Type | Default | Description | |---|---|---|---| | limit | number | 1 | Number of results | | country | string | — | Restrict to a country (ISO2) |

import { nearest } from '@novaedgedigitallabs/citykit';

const [city] = nearest({ lat: 48.8584, lng: 2.2945 });
// → { city: "Paris", country: "France", ... }

distance(from, to)

Calculate the Haversine distance between two cities or coordinate pairs.

distance(
  from: string | { lat: number; lng: number },
  to: string | { lat: number; lng: number }
): DistanceResult | null
import { distance } from '@novaedgedigitallabs/citykit';

distance('Mumbai', 'Delhi');
// → { km: 1153.64, miles: 716.84 }

distance('Tokyo', { lat: 40.7128, lng: -74.006 });
// → { km: 10846.97, miles: 6739.99 }

withinRadius(coords, radiusKm, options?)

Find all cities within a radius. Results sorted by distance ascending (nearest first).

withinRadius(
  coords: { lat: number; lng: number },
  radiusKm: number,
  options?: WithinRadiusOptions
): City[]

| Option | Type | Default | Description | |---|---|---|---| | country | string | — | Filter within a country (ISO2) | | limit | number | — | Max results |

import { withinRadius } from '@novaedgedigitallabs/citykit';

withinRadius({ lat: 22.7196, lng: 75.8577 }, 100);
// → [{ city: "Indore", ... }, { city: "Ujjain", ... }, ...]

withinRadius({ lat: 22.7196, lng: 75.8577 }, 100, { country: 'IN' });

getBoundingBox(lat, lng, radiusKm) ✨ New

Returns a geographic bounding box around a point — useful for pre-filtering before precise Haversine queries.

getBoundingBox(lat: number, lng: number, radiusKm: number): BoundingBox
import { getBoundingBox } from '@novaedgedigitallabs/citykit';

getBoundingBox(28.6139, 77.209, 100);
// → { north: 29.51, south: 27.71, east: 78.42, west: 76.00 }

Returns { north, south, east, west } — all values clamped to valid lat/lng ranges.


byCountry(iso2)

Get all cities for a country.

byCountry(iso2: string): City[]
byCountry('JP');  // → 1,370 cities in Japan

capitals(iso2?)

Get capital cities. Without arguments, returns all national capitals. With ISO2, returns national + state/province capitals for that country.

capitals(iso2?: string): City[]
capitals();       // → all 242 national capitals
capitals('IN');   // → Delhi + all Indian state capitals

byAdmin(adminName, iso2?)

Filter by admin name (state/province). Case-insensitive substring match. Sorted by population descending.

byAdmin(adminName: string, iso2?: string): City[]
import { byAdmin } from '@novaedgedigitallabs/citykit';

byAdmin('Maharashtra', 'IN');
// → [{ city: "Mumbai", population: 18978000, ... }, ...]

byAdmin('California');
// → all California cities, any country

byPopulation(options)

Filter cities by population range.

byPopulation(options: PopulationOptions): City[]

| Option | Type | Default | Description | |---|---|---|---| | min | number | — | Minimum population (inclusive) | | max | number | — | Maximum population (inclusive) | | sort | 'asc' \| 'desc' | 'desc' | Sort order | | limit | number | — | Max results |

byPopulation({ min: 10_000_000, limit: 5 });
// → [{ city: "Tokyo", population: 37785000, ... }, ...]

byContinent(continent)

Get all cities on a continent (case-insensitive).

byContinent(continent: string): City[]
byContinent('Asia');    // all Asian cities
byContinent('Europe');  // all European cities

getByIso2(iso2)

Get country info and all its cities.

getByIso2(iso2: string): CountryInfo | null
getByIso2('DE');
// → { country: "Germany", iso2: "DE", iso3: "DEU", cities: [...1782 cities] }

getCity(name, iso2?)

Get a single city by exact name, optionally scoped to a country.

getCity(name: string, iso2?: string): City | null
getCity('Paris');        // → Paris, France (highest population match)
getCity('Paris', 'US'); // → Paris, United States

getCountryMeta(iso2) ✨ New

Get static metadata for any country: timezone offset, currency code, and calling code.

getCountryMeta(iso2: string): CountryMeta | undefined
interface CountryMeta {
  timezone: number;    // UTC offset in hours (e.g. 5.5 for India)
  currency: string;    // ISO 4217 code (e.g. "INR")
  callingCode: string; // E.164 prefix (e.g. "+91")
}
import { getCountryMeta } from '@novaedgedigitallabs/citykit';

getCountryMeta('IN');
// → { timezone: 5.5, currency: "INR", callingCode: "+91" }

getCountryMeta('DE');
// → { timezone: 1, currency: "EUR", callingCode: "+49" }

getCountryMeta('XX');
// → undefined

getCountryContinent(iso2) ✨ New

Resolve an ISO2 country code to its continent name.

getCountryContinent(iso2: string): string
import { getCountryContinent } from '@novaedgedigitallabs/citykit';

getCountryContinent('IN'); // → "Asia"
getCountryContinent('FR'); // → "Europe"
getCountryContinent('BR'); // → "South America"
getCountryContinent('AU'); // → "Oceania"
getCountryContinent('XX'); // → ""

random(options?)

Get a random city, optionally filtered by country or continent.

random(options?: RandomOptions): City | null
random({ continent: 'Europe' });
// → { city: "Rome", country: "Italy", ... }

listCountries()

List all unique countries with city count, sorted alphabetically.

listCountries(): CountryListItem[]
listCountries();
// → [
//   { country: "Afghanistan", iso2: "AF", iso3: "AFG", count: 73 },
//   ...242 countries
// ]

getContinentNames()

Get all continent names with correct capitalization.

getContinentNames(): string[]
getContinentNames();
// → ['Africa', 'Asia', 'Europe', 'North America', 'Oceania', 'South America']

stats()

Aggregated dataset statistics.

stats(): DatasetStats
stats();
// → {
//     totalCities: 49992,
//     totalCountries: 242,
//     totalCapitals: 242,
//     largestCity: { city: "Tokyo", population: 37785000, ... },
//     smallestCity: { city: "Adamstown", ... },
//     averagePopulation: 111352.45,
//     totalPopulation: 4561848912
//   }

India-Specific Utilities ✨ New

A dedicated set of helpers for Indian cities, fully typed and population-sorted.

getIndianCities()

All 7,200+ Indian cities from the dataset.

getIndianCities(): City[]
import { getIndianCities } from '@novaedgedigitallabs/citykit';

const cities = getIndianCities(); // → 7,200+ cities, iso2 === "IN"

getCitiesByState(state)

Filter Indian cities by state/UT name. Supports plain English — diacritics in dataset names (e.g. "Mahārāshtra") are normalized automatically. Sorted by population descending.

getCitiesByState(state: string): City[]
import { getCitiesByState } from '@novaedgedigitallabs/citykit';

getCitiesByState('Maharashtra');
// → [{ city: "Mumbai", population: 18978000, ... }, { city: "Pune", ... }, ...]

getCitiesByState('Tamil');     // partial match — returns Tamil Nadu cities
getCitiesByState('Uttar Pradesh');

getCityTier(cityName)

Classify an Indian city's tier based on population. Returns null if city not found or has no population data.

getCityTier(cityName: string): IndianCityTier | null
// IndianCityTier = 'Tier 1' | 'Tier 2' | 'Tier 3'

| Tier | Threshold | Examples | |---|---|---| | Tier 1 | population ≥ 4,000,000 | Mumbai, Delhi, Bangalore, Hyderabad | | Tier 2 | population ≥ 500,000 | Indore, Patna, Vadodara, Coimbatore | | Tier 3 | population < 500,000 | Smaller cities & towns |

import { getCityTier } from '@novaedgedigitallabs/citykit';

getCityTier('Mumbai');    // → "Tier 1"
getCityTier('Indore');    // → "Tier 2"
getCityTier('Khandwa');   // → "Tier 3"
getCityTier('FakeCity');  // → null

getIndianStates()

All unique Indian state/UT names in the dataset, sorted alphabetically.

getIndianStates(): string[]
import { getIndianStates } from '@novaedgedigitallabs/citykit';

getIndianStates();
// → ["Andaman and Nicobar", "Andhra Pradesh", "Arunachal Pradesh", ..., "West Bengal"]

getTierThresholds()

Returns the population thresholds used by getCityTier().

getTierThresholds(): { tier1: number; tier2: number }
getTierThresholds();
// → { tier1: 4000000, tier2: 500000 }

Enriched City Object ✨ New

Every City object now includes enriched metadata fields derived from the country's static profile.

interface City {
  // Core fields
  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;

  // Enriched fields (v1.3+)
  isCapital: boolean;    // true only for national capitals (capital === 'primary')
  continent: string;     // e.g. "Asia", "Europe", "North America"
  timezone: number;      // UTC offset in hours (e.g. 5.5 for India)
  currency: string;      // ISO 4217 code (e.g. "INR", "EUR", "USD")
  callingCode: string;   // E.164 prefix (e.g. "+91", "+49")
}
import { getCity } from '@novaedgedigitallabs/citykit';

const city = getCity('Mumbai', 'IN');
// → {
//     city: "Mumbai",
//     country: "India",
//     iso2: "IN",
//     isCapital: false,
//     continent: "Asia",
//     timezone: 5.5,
//     currency: "INR",
//     callingCode: "+91",
//     population: 18978000,
//     ...
//   }

Lite Version

For bundle-size-sensitive apps, use the lite import — only cities with population ≥ 500,000 (1,422 cities, 141 countries).

import { search, distance, autocomplete } from '@novaedgedigitallabs/citykit/lite';

// Same API, smaller dataset
search('london');
// → [{ city: "London", population: 11262000, currency: "GBP", ... }]

Bundle Comparison

| Version | Cities | Data Size | |---|---|---| | Full | 49,992 | ~5.0 MB | | Lite | 1,422 | ~140 KB |


TypeScript Support

CityKit is written in TypeScript and ships full type declarations.

import type {
  City,
  CountryMeta,
  BoundingBox,
  IndianCityTier,
  AutocompleteOptions,
  SearchOptions,
  NearestOptions,
  DistanceResult,
  CountryInfo,
  CountryListItem,
  PopulationOptions,
  FuzzySearchOptions,
  RandomOptions,
  DatasetStats,
  WithinRadiusOptions,
} from '@novaedgedigitallabs/citykit';

Data Source

City data sourced from the SimpleMaps World Cities Database — a comprehensive dataset covering cities worldwide with population, coordinates, and administrative data.


Support

If citykit saved you time → novaedgedigitallabs.tech/pay

License

MIT © NovaEdge Digital Labs