dr5hn/countries-states-cities-database: A 153,765-City Dataset in Twelve Formats
🌍 Discover our global repository of countries, states, and cities! 🏙️ Get comprehensive data in JSON, SQL, PSQL, SQLSERVER, MONGODB, SQLITE, XML, YAML, and CSV formats. Access ISO2, ISO3 codes, country code, capital, native language, timezones (for countries), and more. #countries #states #cities
At a glance
- What is it?
- The repository publishes countries, states, cities and postcodes as JSON, SQL, PSQL, SQL Server, MongoDB, SQLite, XML, YAML and CSV exports, with a managed REST API and a browser export tool alongside it. The data is free under ODbL-1.0, but attribution is a licence condition, not a courtesy.
- Who is it for?
- Adopt this repository if you need a broad, format-flexible reference table for country, state and city pickers, and if you can carry the ODbL attribution requirement into your product. Do not adopt it if you need authoritative postal addressing per country, if your compliance team cannot accept a share-alike database licence, or if you cannot tolerate a dataset that is refreshed on a release cadence rather than continuously.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 12 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the dataset actually contains, and who reaches for it
The README lists totals directly: 6 regions, 22 sub regions, 250 countries, 5,299 states or regions or municipalities, 153,765 cities or towns or districts, 844,248 postcodes across 125 countries, and 427 timezones with what it describes as 100 percent IANA coverage. The last updated date printed in the README is July 29, 2026, which matches the v3.2-export.7 release published on 2026-07-29.
The audience is narrow and practical. Anyone building an address form needs a country list, then a state list that depends on the chosen country, then a city list that depends on the state. The same shape appears in shipping calculators, tax jurisdiction tables, CRM dropdowns and analytics normalisation. Doing this by hand means maintaining thousands of rows that change when a country renames a province or a city splits.
What the dataset is not is an addressing authority. Postcodes cover 125 countries, so more than half the country rows have no postcode data behind them. If your requirement is validated delivery addresses, this repository is a starting vocabulary, not a verification service.
How the exports are organised and how a lookup flows
The repository is a data publication, not a runtime service. The top level holds one directory per output family: csv/, json/, psql/, sql/, sqlite/, sqlserver/, xml/, yml/, parquet/, duckdb/, geojson/, toon/ and prisma/. Each release attaches the same data as gzipped assets, so the directory tree and the release assets are two views of one build.
The hierarchy is three levels deep plus postcodes. A country row carries ISO2 and ISO3 codes and a numeric country code, a capital, a region and sub region, and timezones. A state row points at a country. A city row points at a state. Postcodes attach to cities in the countries that have them. That means a cascading form is three indexed lookups, and the join key you choose matters: ISO2 is short and readable, but the numeric code is the one that will not be confused with a state abbreviation.
Two files at the top level explain modelling decisions rather than data. TYPE_FIELD.md and MULTI_LEVEL_TERRITORIES.md exist because some countries do not fit a country-state-city pyramid, and the repository documents how it handles those cases instead of forcing every territory into three levels. If your product assumes exactly three levels, read MULTI_LEVEL_TERRITORIES.md before you write the schema.
Installing and running a first lookup
There is no install step for the data itself. You download a release asset, or you pull the directory you need. The README gives this example for the gzipped city export, which downloads the latest release asset and decompresses it in place.
curl -LO https://github.com/dr5hn/countries-states-cities-database/releases/latest/download/json-cities.json.gz
gunzip json-cities.json.gzAfter that you have json-cities.json in the working directory. The README's own description of the file set is that every format ships as a .gz asset on each GitHub Release, so the same pattern applies to the CSV and SQL variants by changing the asset name.
If you would rather not manage files, the README documents a managed REST API. The curl example it gives queries the cities of a state, and requires an API key in the X-CSCAPI-KEY header.
curl https://api.countrystatecity.in/v1/countries/IN/states/MH/cities \
-H "X-CSCAPI-KEY: $YOUR_API_KEY"For Python, the README points at an official client. It installs from PyPI and reads the key from an environment variable, then exposes a context manager with methods such as get_states_of_country.
pip install countrystatecity-api
export CSC_API_KEY="YOUR_API_KEY"from countrystatecity import CountryStateCity
with CountryStateCity() as client:
states = client.get_states_of_country("IN")
print([state["name"] for state in states[:3]])The README does not document the response schema of that call beyond the state name field used in the example, so check the OpenAPI spec repository it links before you build a parser around it. The same README also notes that the API has a free tier for prototyping and paid tiers for production, which is the line where an offline export and a hosted service stop being interchangeable.
Where the offline exports stop being enough
The first limitation is freshness. Data arrives in exports tied to releases, and the release history shows a cadence of roughly weeks to months: v3.2-export.5 on 2026-06-21, v3.2-export.6 on 2026-07-11, v3.2-export.7 on 2026-07-29. The README's own last updated line is July 29, 2026. If your product needs a change reflected the day it happens, an export cannot do that, and the README positions the REST API as the managed alternative for exactly that reason.
The second limitation is postcode coverage. 844,248 postcodes across 125 countries means the postcode files are useful for some markets and empty for others, and the README does not enumerate which countries are included. Treat the postcode dataset as partial until you have checked your own target countries in the file.
The third is structural. Countries that do not map cleanly onto country, state, city are handled through documented conventions rather than a uniform shape, which is why MULTI_LEVEL_TERRITORIES.md exists. Any code that assumes every city has a parent state will hit those cases.
The fourth is licensing rather than data. ODbL-1.0 is a database licence with an attribution requirement, and the README states that plainly. Attribution is a condition of use, and the share-alike terms of an open database licence can affect how you redistribute a derived database. That is a question for your own legal review, not something the repository can settle for you.
How it compares with GeoNames and with the managed API tier
GeoNames is the closest widely used alternative and takes a different approach. It is a gazetteer: it records places with coordinates, feature classes and alternate names, and it lets you query by proximity or bounding box. This repository is an administrative hierarchy. It gives you the parent chain from country to state to city and the codes that go with it, and the geojson/ directory is the only place where geometry enters the picture. If you need to answer which cities fall inside a radius, GeoNames is built for that and this dataset is not. If you need to populate a three-level address form, the hierarchy here is already shaped for the job and GeoNames would require you to reconstruct the parent chain yourself.
The second comparison is internal. The README recommends the managed REST API and the export tool as the production path, and describes the API as actively maintained and billed for sustainability. The offline exports are versioned snapshots. The practical difference is operational: an export is a file you version, test and redeploy, while the API is a dependency with a key, a rate tier and an uptime you do not control. Neither is wrong, but mixing them without deciding which is the source of truth leads to two datasets that drift apart.
Maintenance cadence, licence obligations and what to verify
The repository is not archived, and the last push was on 2026-09-18. The release history shows export tags appearing through mid-2026, so the dataset is being rebuilt rather than frozen. That still leaves you with a manual upgrade: nothing in the README describes an automatic update path for a downloaded export, and the README does not document rollback if a new export breaks a downstream join. Plan for the upgrade as a data migration you test, not a file swap.
The licence is ODbL-1.0. The README states attribution is required and links the LICENSE file. For an application that displays country and city names, the practical obligation is a visible credit, but the share-alike provisions apply to derived databases, and whether your particular use creates one is a legal question. Read the LICENSE file and the ODbL text rather than relying on a summary.
If you want the data without maintaining it, the README points at the API, the export tool at export.countrystatecity.in, and the OpenAPI spec at the csc-swagger repository. Those are the three places to look before you decide to vendor a snapshot.
Editorial conclusion
Adopt this repository if you need a broad, format-flexible reference table for country, state and city pickers, and if you can carry the ODbL attribution requirement into your product. Do not adopt it if you need authoritative postal addressing per country, if your compliance team cannot accept a share-alike database licence, or if you cannot tolerate a dataset that is refreshed on a release cadence rather than continuously. Before committing, download the gzipped export for your target format from the latest GitHub Release, check that the country and state rows you depend on are present in that specific file, and confirm whether the postcode coverage you need falls inside the 125 countries the README lists. The repository is not archived and the last push was on 2026-09-18, so the export cadence is the thing to measure against your own update window.
Frequently asked questions
Can I get a free list of countries, states and cities from dr5hn/countries-states-cities-database?
Yes. The repository publishes the full dataset as gzipped assets on each GitHub Release and as directories in the repository itself, covering 250 countries, 5,299 states and 153,765 cities. The licence is ODbL-1.0, and the README states that attribution is required.
Does dr5hn/countries-states-cities-database cover every city in the world?
The README reports 153,765 cities, towns and districts, plus 844,248 postcodes across 125 countries. It does not claim complete global coverage, and the postcode files in particular cover only those 125 countries.
Is the country state city API free to use?
The README describes a free tier for prototyping and paid tiers for production, with plans compared on the project's pricing page. The offline exports in the repository are separate from the API and are published under ODbL-1.0.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/dr5hn-countries-states-cities-database)