Skip to main content

Rwanda Geo Data

Rwanda's administrative divisions for JavaScript/TypeScript and Python: 5 provinces → 30 districts → 416 sectors → 2,149 cells → 14,837 villages.

Zero dependencies. Lookups are case-insensitive. District names are unique, so you only pass the district (no province) when looking up sectors, cells and villages.

JavaScript / TypeScript

npm install @linkfy-connect/rwanda-geo-data

Works in Node, and in any bundler-based framework (React, Next.js, Vue, Nuxt, Angular, Svelte/SvelteKit, Astro, Remix, React Native, Vite, webpack) via ESM, CommonJS and bundled TypeScript types.

import { getProvinces, getDistricts, getSectors, getCells, getVillages, search } from '@linkfy-connect/rwanda-geo-data';

getProvinces();                                  // ['East', 'Kigali', 'North', 'South', 'West']
getDistricts('East');                            // ['Bugesera', 'Gatsibo', ...]
getSectors('Bugesera');                          // ['Gashora', 'Juru', ...]
getCells('Bugesera', 'Gashora');                 // ['Biryogo', 'Kabuye', ...]
getVillages('Bugesera', 'Gashora', 'Biryogo');   // ['Bidudu', 'Biryogo', ...]

React: cascading dropdowns

import { useState } from 'react';
import { getProvinces, getDistricts, getSectors, getCells, getVillages } from '@linkfy-connect/rwanda-geo-data';

const LEVELS = ['province', 'district', 'sector', 'cell', 'village'];

export default function AddressPicker() {
  const [a, setA] = useState({});

  // Changing a level clears every level below it.
  const choose = (level, value) => {
    const keep = LEVELS.slice(0, LEVELS.indexOf(level));
    setA({ ...Object.fromEntries(keep.map((k) => [k, a[k]])), [level]: value });
  };

  const options = {
    province: getProvinces(),
    district: a.province ? getDistricts(a.province) : [],
    sector: a.district ? getSectors(a.district) : [],
    cell: a.sector ? getCells(a.district, a.sector) : [],
    village: a.cell ? getVillages(a.district, a.sector, a.cell) : [],
  };

  return LEVELS.map((level) => (
    <select key={level} value={a[level] || ''} disabled={!options[level].length}
            onChange={(e) => choose(level, e.target.value)}>
      <option value="">Select {level}</option>
      {options[level].map((o) => <option key={o}>{o}</option>)}
    </select>
  ));
}

Vue 3

<script setup>
import { ref, computed } from 'vue';
import { getProvinces, getDistricts } from '@linkfy-connect/rwanda-geo-data';
const province = ref('');
const districts = computed(() => getDistricts(province.value));
</script>
<template>
  <select v-model="province"><option v-for="p in getProvinces()" :key="p">{{ p }}</option></select>
  <select><option v-for="d in districts" :key="d">{{ d }}</option></select>
</template>

Angular, Svelte, Next.js, Nuxt

Same import everywhere: import { getDistricts } from '@linkfy-connect/rwanda-geo-data'. In Next.js/Nuxt it also works in server code (API routes, server components).

The whole dataset is about 190 kB in the bundle (roughly 40 kB gzipped). To keep it out of the initial bundle, load it lazily:

const geo = await import('@linkfy-connect/rwanda-geo-data');

API

Function Returns
getProvinces() string[]
getDistricts(province?) districts of a province, or all 30
getProvinceOf(district) province name or undefined
getSectors(district) string[]
getCells(district, sector) string[]
getVillages(district, sector, cell) string[]
isValidAddress({province, district, sector?, cell?, village?}) boolean
search(query, {levels?, limit?}) [{level, name, province, district?, ...}]
getStats() counts per level
data the raw nested object

Python

pip install rwanda-geo-data

Python 3.8+, standard library only.

import rwanda_geo_data as geo

geo.get_provinces()                                  # ['East', 'Kigali', 'North', 'South', 'West']
geo.get_districts("East")                            # ['Bugesera', 'Gatsibo', ...]
geo.get_sectors("Bugesera")                          # ['Gashora', 'Juru', ...]
geo.get_cells("Bugesera", "Gashora")                 # ['Biryogo', 'Kabuye', ...]
geo.get_villages("Bugesera", "Gashora", "Biryogo")   # ['Bidudu', 'Biryogo', ...]
geo.is_valid_address("East", "Bugesera", "Gashora")  # True
geo.search("gashora", levels=["sector"])
geo.DATA                                             # raw nested dict

FastAPI

from fastapi import FastAPI
import rwanda_geo_data as geo

app = FastAPI()

@app.get("/districts/{province}")
def districts(province: str):
    return geo.get_districts(province)

@app.get("/sectors/{district}")
def sectors(district: str):
    return geo.get_sectors(district)

Django / Flask

Call the same functions inside any view, serializer or form validator, for example geo.is_valid_address(...) in a form's clean().

Development

npm test            # builds dist/, syncs data to python/, runs JS tests
cd python && python -m unittest discover -s tests

data/rwanda-geo-data.json is the single source of truth. Edit it, then run npm run build: this regenerates dist/ and copies the data into the Python package.

Publishing

# npm
npm login
npm publish            # use `npm publish --access public` for a scoped name

# PyPI
cd python
pip install build twine
python -m build
twine upload dist/*

Bump the version in both package.json and python/pyproject.toml for each release.

License

MIT

Metadata

Release files for rwanda-geo-data 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rwanda-geo-data 1.0.1
File Size Uploaded
rwanda_geo_data-1.0.1.tar.gz 76.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rwanda-geo-data 1.0.1
File Interpreter ABI Platform
rwanda_geo_data-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 152.0 kB

Release files / rwanda_geo_data-1.0.1.tar.gz

Download URL rwanda_geo_data-1.0.1.tar.gz
Size 76.9 kB
Tags Source
SHA-256 checksum
How to use checksums
63d0db56a4e05ca96b1fcfc4d186051661a21e2d872a89a8264ef4aa833139a2
BLAKE2b-256 checksum
How to use checksums
76496d699397c3a26800406c438d83d521f121147929a192c4d845d4238a8996
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / rwanda_geo_data-1.0.1-py3-none-any.whl

Download URL rwanda_geo_data-1.0.1-py3-none-any.whl
Size 75.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
565325708ee718ca334b19a8ded65bd412fcbfb2424ff0b0a997c5829fb82e25
BLAKE2b-256 checksum
How to use checksums
47e4930180f2fd450141c8d9ecf4083ecd4083d122fd7787560ced72cc724888
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

1.1.0

2 release files

This release

1.0.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page