A simple, powerful TypeScript library for working with Rwanda's administrative divisions. Get information about provinces, districts, sectors, cells, and villages with ease!
Perfect for building:
- 📝 Address forms with cascading dropdowns
- 🗺️ Location-based applications
- 📊 Geographic data analysis
- 🏢 Administrative management systems
- 📱 Mobile apps needing Rwanda location data
- ✅ Complete Data - All 5 provinces, 30 districts, 416 sectors, 2,148 cells, and 14,837 villages
- ✅ Easy to Use - Simple, intuitive API
- ✅ Zero Dependencies - Lightweight and fast
- ✅ Type-Safe - Full TypeScript support
- ✅ Well Tested - 98%+ test coverage (109 tests)
- ✅ Secure - Zero vulnerabilities, security audited
- ✅ Production Ready - Used in real-world applications
npm install @devrw/rwanda-locationor with yarn:
yarn add @devrw/rwanda-locationimport{rwandaLocation}from'@devrw/rwanda-location';// Get all provincesconstprovinces=rwandaLocation.getProvinces();console.log(provinces);// [// { code: 1, name: 'KIGALI' },// { code: 2, name: 'SOUTH' },// { code: 3, name: 'WEST' },// { code: 4, name: 'NORTH' },// { code: 5, name: 'EAST' }// ]// Get districts in a provinceconstkigaliDistricts=rwandaLocation.getDistricts(1);console.log(kigaliDistricts);// [// { code: 101, name: 'Nyarugenge', provinceCode: 1, provinceName: 'KIGALI' },// { code: 102, name: 'Gasabo', provinceCode: 1, provinceName: 'KIGALI' },// { code: 103, name: 'Kicukiro', provinceCode: 1, provinceName: 'KIGALI' }// ]This is the most common use case - building address forms where each dropdown depends on the previous selection:
import{RwandaLocation}from'@devrw/rwanda-location';constrw=newRwandaLocation();// Step 1: User selects a provinceconstprovinces=rw.getProvinces();// Show provinces in dropdown// Step 2: When province is selected, load its districtsconstselectedProvinceCode=1;// User selected KIGALIconstdistricts=rw.getDistricts(selectedProvinceCode);// Show districts in next dropdown// Step 3: When district is selected, load its sectorsconstselectedDistrictCode=101;// User selected Nyarugengeconstsectors=rw.getSectors(selectedDistrictCode);// Show sectors in next dropdown// Step 4: When sector is selected, load its cellsconstselectedSectorCode='010101';// User selected Gitegaconstcells=rw.getCells(selectedSectorCode);// Show cells in next dropdown// Step 5: When cell is selected, load its villagesconstselectedCellCode=1010101;// User selected Akabahiziconstvillages=rw.getVillages(selectedCellCode);// Show villages in final dropdown// Step 6: Get complete informationconstselectedVillageCode=101010102;constfullInfo=rw.getVillageByCode(selectedVillageCode);console.log(fullInfo);// {// code: 101010102,// name: 'Gihanga',// cellCode: 1010101,// cellName: 'Akabahizi',// sectorCode: '010101',// sectorName: 'Gitega',// districtCode: 101,// districtName: 'Nyarugenge',// provinceCode: 1,// provinceName: 'KIGALI'// }Search across all administrative levels:
// Search for locations containing "Kigali"constresults=rw.search({query: 'Kigali',limit: 10});results.forEach((location)=>{console.log(`${location.village_name}, ${location.sector_name}, ${location.district_name}`);});// Find a province by nameconstprovince=rw.getProvinceByName('KIGALI');// Find a district by codeconstdistrict=rw.getDistrictByCode(101);// Get all sectors in a districtconstsectors=rw.getSectors(101);// Get complete hierarchy for a villageconstvillage=rw.getVillageByCode(101010102);// Find all locations in a specific areaconstlocations=rw.query({provinceCode: 1,districtCode: 101,sectorName: 'Gitega',});// Query by names (case-insensitive)constbyName=rw.query({provinceName: 'kigali'});Get all 5 provinces in Rwanda.
constprovinces=rw.getProvinces();// Returns: Province[]Get a specific province by its code (1-5).
constkigali=rw.getProvinceByCode(1);// Returns: Province | nullGet a province by name (case-insensitive).
constsouth=rw.getProvinceByName('south');// Returns: Province | nullGet all districts, or filter by province.
// All districtsconstallDistricts=rw.getDistricts();// Districts in specific provinceconstkigaliDistricts=rw.getDistricts(1);// Returns: District[]Get a specific district by its code.
constnyarugenge=rw.getDistrictByCode(101);// Returns: District | nullGet all sectors, or filter by district/province.
// All sectorsconstallSectors=rw.getSectors();// Sectors in a districtconstdistrictSectors=rw.getSectors(101);// Sectors in a provinceconstprovinceSectors=rw.getSectors(undefined,1);// Returns: Sector[]Get a specific sector by its code.
constsector=rw.getSectorByCode('010101');// Returns: Sector | nullGet all cells, or filter by sector/district/province.
// All cellsconstallCells=rw.getCells();// Cells in a sectorconstsectorCells=rw.getCells('010101');// Cells in a districtconstdistrictCells=rw.getCells(undefined,101);// Returns: Cell[]Get a specific cell by its code.
constcell=rw.getCellByCode(1010101);// Returns: Cell | nullGet all villages, or filter by cell/sector/district/province.
// All villagesconstallVillages=rw.getVillages();// Villages in a cellconstcellVillages=rw.getVillages(1010101);// Villages in a sectorconstsectorVillages=rw.getVillages(undefined,'010101');// Returns: Village[]Get a specific village with its complete hierarchy.
constvillage=rw.getVillageByCode(101010102);// Returns: Village | null// Village includes: province, district, sector, cell, and village infoSearch for locations by name across all levels.
// Basic searchconstresults=rw.search({query: 'Kigali'});// Case-sensitive searchconstexactResults=rw.search({query: 'KIGALI',caseSensitive: true,});// Limited resultsconsttopResults=rw.search({query: 'gitega',limit: 10,});// Returns: LocationData[]Query locations with multiple filters.
constfiltered=rw.query({provinceCode: 1,districtCode: 101,sectorName: 'Gitega',});// Returns: LocationData[]Get counts of all administrative divisions.
conststats=rw.getStatistics();// Returns:// {// totalProvinces: 5,// totalDistricts: 30,// totalSectors: 416,// totalCells: 2148,// totalVillages: 14837// }Get complete hierarchy for a village (alias for getVillageByCode).
consthierarchy=rw.getHierarchy(101010102);// Returns: Village | nullGet structured path for breadcrumb navigation.
constpath=rw.getFullPath(101010102);// Returns:// {// province: { code: 1, name: 'KIGALI' },// district: { code: 101, name: 'Nyarugenge', ... },// sector: { code: '010101', name: 'Gitega', ... },// cell: { code: 1010101, name: 'Akabahizi', ... },// village: { code: 101010102, name: 'Gihanga', ... }// }interfaceProvince{code: number;// 1-5name: string;// 'KIGALI', 'SOUTH', 'WEST', 'NORTH', 'EAST'}interfaceDistrict{code: number;name: string;provinceCode: number;provinceName: string;}interfaceSector{code: string;name: string;districtCode: number;districtName: string;provinceCode: number;provinceName: string;}interfaceCell{code: number;name: string;sectorCode: string;sectorName: string;districtCode: number;districtName: string;provinceCode: number;provinceName: string;}interfaceVillage{code: number;name: string;cellCode: number;cellName: string;sectorCode: string;sectorName: string;districtCode: number;districtName: string;provinceCode: number;provinceName: string;}| Code | Province Name |
|---|---|
| 1 | KIGALI |
| 2 | SOUTH |
| 3 | WEST |
| 4 | NORTH |
| 5 | EAST |
Rwanda's administrative hierarchy:
Country (Rwanda)
└── Province (5)
└── District (30)
└── Sector (416)
└── Cell (2,148)
└── Village (14,837)
importReact,{useState}from'react';import{rwandaLocation}from'@devrw/rwanda-location';functionAddressForm(){const[selectedProvince,setSelectedProvince]=useState('');const[selectedDistrict,setSelectedDistrict]=useState('');const[districts,setDistricts]=useState([]);constprovinces=rwandaLocation.getProvinces();consthandleProvinceChange=(provinceCode)=>{setSelectedProvince(provinceCode);setDistricts(rwandaLocation.getDistricts(parseInt(provinceCode)));setSelectedDistrict('');};return(<div><selectonChange={(e)=>handleProvinceChange(e.target.value)}><optionvalue="">SelectProvince</option>{provinces.map(p=>(<optionkey={p.code}value={p.code}>{p.name}</option>))}</select>{selectedProvince&&(<selectonChange={(e)=>setSelectedDistrict(e.target.value)}><optionvalue="">SelectDistrict</option>{districts.map(d=>(<optionkey={d.code}value={d.code}>{d.name}</option>))}</select>)}</div>);}constexpress=require('express');const{ rwandaLocation }=require('@devrw/rwanda-location');constapp=express();app.get('/api/provinces',(req,res)=>{constprovinces=rwandaLocation.getProvinces();res.json(provinces);});app.get('/api/districts/:provinceCode',(req,res)=>{constdistricts=rwandaLocation.getDistricts(parseInt(req.params.provinceCode));res.json(districts);});app.listen(3000);functionvalidateAddress(data: {provinceCode: number;districtCode: number;sectorCode: string}){// Check province existsconstprovince=rw.getProvinceByCode(data.provinceCode);if(!province){return{valid: false,error: 'Invalid province'};}// Check district exists and belongs to provinceconstdistrict=rw.getDistrictByCode(data.districtCode);if(!district||district.provinceCode!==data.provinceCode){return{valid: false,error: 'Invalid district for this province'};}// Check sector exists and belongs to districtconstsector=rw.getSectorByCode(data.sectorCode);if(!sector||sector.districtCode!==data.districtCode){return{valid: false,error: 'Invalid sector for this district'};}return{valid: true};}Q: Getting null or empty results?
A: Make sure you're using valid codes. Province codes are 1-5, district codes start from 101, etc.
// ❌ Wrongconstdistricts=rw.getDistricts(999);// Returns []// ✅ Correctconstdistricts=rw.getDistricts(1);// Returns Kigali districtsQ: TypeScript errors?
A: Ensure you have TypeScript installed and configured:
npm install --save-dev typescript @types/nodeQ: Import errors?
A: Use the correct import syntax:
// ES6import{rwandaLocation,RwandaLocation}from'@devrw/rwanda-location';// CommonJSconst{ rwandaLocation }=require('@devrw/rwanda-location');- Reuse instances - Create one instance and reuse it:
// ✅ Goodimport{rwandaLocation}from'@devrw/rwanda-location';constprovinces=rwandaLocation.getProvinces();// ❌ Less efficientimport{RwandaLocation}from'@devrw/rwanda-location';constrw1=newRwandaLocation();constrw2=newRwandaLocation();- Check for null - Always validate results:
constprovince=rw.getProvinceByCode(userInput);if(!province){console.error('Province not found');return;}// Use province safely- Use TypeScript - Get full type safety:
import{RwandaLocation,Province}from'@devrw/rwanda-location';constrw=newRwandaLocation();constprovinces: Province[]=rw.getProvinces();The library is optimized for speed:
| Operation | Time | Records |
|---|---|---|
| Get all provinces | < 1ms | 5 |
| Get all districts | < 5ms | 30 |
| Get all sectors | < 20ms | 416 |
| Get all cells | < 50ms | 2,148 |
| Get all villages | < 100ms | 14,837 |
| Search (with limit) | < 10ms | Variable |
- ⚡ Zero dependencies - Fast installation
- 📦 Lightweight - ~7MB (mostly location data)
- 🚀 Efficient - Uses Maps for O(1) lookups
- 💾 Memory efficient - Data loaded once
This package is secure and production-ready:
- ✅ Zero vulnerabilities - Regularly audited with
npm audit - ✅ Zero runtime dependencies - No third-party code
- ✅ No code execution - Pure data access only
- ✅ Type-safe - TypeScript strict mode
- ✅ Well tested - 98%+ code coverage
Security Contact: info@jnkindilogs.xyz
Works in all modern browsers and Node.js:
- ✅ Node.js >= 14.0.0
- ✅ Chrome, Firefox, Safari, Edge (latest versions)
- ✅ React, Vue, Angular applications
- ✅ Next.js, Nuxt.js applications
We welcome contributions! Here's how:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests (
npm test) - Commit (
git commit -m 'Add amazing feature') - Push (
git push origin feature/amazing-feature) - Open a Pull Request
# Run tests
npm test# Run tests in watch mode
npm run test:watch
# Build the project
npm run build
# Lint code
npm run lint- 📄 License: Updated Read me to capture license change
- 📦 Package: Updated package metadata
- 📄 License: Changed from Apache-2.0 to MIT license for better compatibility
- 📦 Package: Updated package metadata
- 🔒 Security: Fixed all vulnerabilities (0 vulnerabilities)
- ✅ Testing: Enhanced test coverage to 98%+
- 📚 Documentation: Comprehensive documentation
- 🔧 Improvements: Better TypeScript types
- 🎯 Performance: Optimized query performance
- 📦 Package: Improved package structure
- 🎉 Initial release
- ✨ Complete Rwanda location data
- 📖 Basic documentation
Need help? We're here for you:
- 📧 Email: info@jnkindilogs.xyz
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
MIT License - see the LICENSE file for details.
- Jacques Nyilinkindi - info@jnkindilogs.xyz
- Theo Okafor - theo.okafor@yahoo.com
Thanks to everyone who contributed to this project and to the Rwanda government for the official administrative data.
Made with ❤️ for Rwanda 🇷🇼
Star us on GitHub if you find this useful!