@olism/bd-geo
v0.1.8
Published
Bangladesh geographical data and utilities
Downloads
562
Maintainers
Readme
@olism/bd-geo
Bangladesh geographical data and utilities for JavaScript and TypeScript.
[!IMPORTANT] Always use the latest version of
@olism/bd-geo.This package is actively maintained and geographical data is continuously being improved and expanded. New releases may include updated geographical data, additional locations, corrections, and API improvements.
Check the latest version on npm before installing or upgrading.
@olism/bd-geo provides structured geographical data for Bangladesh, including:
- Divisions
- Districts
- Upazilas / Thanas
- Unions
- Wards
- Villages
The package is designed for applications such as:
- Address forms
- Location selectors
- Delivery systems
- E-commerce applications
- Real-estate platforms
- Job platforms
- User profiles
- Registration forms
- Location filters
- Bangladesh-focused maps
- Database seed data
Installation
npm
npm install @olism/bd-geoYarn
yarn add @olism/bd-geopnpm
pnpm add @olism/bd-geoGeography Hierarchy
The geographical structure provided by the package is:
Division
│
└── District
│
└── Upazila / Thana
│
└── Area
├── Union
│ └── Village
│
└── WardImportant
UpazilaandThanaare represented by the same geographical level.Areacan be either aunionor award.- A
Villagebelongs to anAreawhose type isunion. - Villages do not belong directly to wards.
Quick Start
Import the functions you need:
import {
getDivisions,
getDistricts,
getUpazilas,
getAreas,
getVillages,
} from "@olism/bd-geo";Then use them directly:
const divisions = getDivisions();
const districts = getDistricts();
const upazilas = getUpazilas();
const areas = getAreas();
const villages = getVillages();API
getDivisions()
Returns all available Bangladesh divisions.
const divisions = getDivisions();Return type:
Division[]Example:
[
{
id: 1,
name: "Barishal",
nameBn: "বরিশাল",
},
{
id: 2,
name: "Chattogram",
nameBn: "চট্টগ্রাম",
},
];getDistricts()
Returns all available Bangladesh districts.
const districts = getDistricts();Return type:
District[]Example:
[
{
id: 1,
name: "Dhaka",
nameBn: "ঢাকা",
divisionId: 3,
},
];getUpazilas()
Returns all available upazilas.
const upazilas = getUpazilas();Return type:
Upazila[]Example:
[
{
id: 1,
name: "Mirpur",
nameBn: "মিরপুর",
districtId: 1,
type: "thana",
},
];getThanas()
[!WARNING]
getThanas()is deprecated.Use
getUpazilas()for new applications.
const thanas = getThanas();It returns the same data as:
getUpazilas();This function is kept for backward compatibility.
Recommended
const upazilas = getUpazilas();Legacy
const thanas = getThanas();getAreas()
Returns all available areas.
An area can be either:
"union";or:
"ward";Example:
const areas = getAreas();Return type:
Area[]Example:
[
{
id: 1,
name: "Mirpur-1",
nameBn: "মিরপুর-১",
upazilaId: 1,
type: "ward",
},
];getVillages()
Returns all available villages.
const villages = getVillages();Return type:
Village[]Example:
[
{
id: 1,
name: "Example Village",
nameBn: "উদাহরণ গ্রাম",
areaId: 10,
},
];A village's areaId references an area where:
area.type === "union";TypeScript Types
The package exports TypeScript types for all geographical levels.
Division
export interface Division {
id: number;
name: string;
nameBn: string;
latitude?: number;
longitude?: number;
}District
export interface District {
id: number;
name: string;
nameBn: string;
divisionId: number;
latitude?: number;
longitude?: number;
}Upazila
An upazila and thana are represented by the same geographical level.
export interface Upazila {
id: number;
name: string;
nameBn: string;
districtId: number;
type?: "upazila" | "thana";
latitude?: number;
longitude?: number;
}The optional type field can distinguish between:
"upazila";and:
"thana";Area
export type AreaType = "union" | "ward";
export interface Area {
id: number;
name: string;
nameBn: string;
upazilaId: number;
type: AreaType;
latitude?: number;
longitude?: number;
}Village
export interface Village {
id: number;
name: string;
nameBn: string;
areaId: number;
latitude?: number;
longitude?: number;
}A village must reference an Area whose type is union.
Relationship IDs
Each geographical level references its parent.
District.divisionId
↓
Division.idUpazila.districtId
↓
District.idArea.upazilaId
↓
Upazila.idVillage.areaId
↓
Area.idExample
Find the division of a district:
const districts = getDistricts();
const divisions = getDivisions();
const district = districts.find((district) => district.id === 1);
const division = divisions.find(
(division) => division.id === district?.divisionId,
);Cascading Address Selector
The package can easily be used to create cascading location selectors.
import {
getDivisions,
getDistricts,
getUpazilas,
getAreas,
getVillages,
} from "@olism/bd-geo";
const divisions = getDivisions();
const districts = getDistricts().filter(
(district) => district.divisionId === selectedDivisionId,
);
const upazilas = getUpazilas().filter(
(upazila) => upazila.districtId === selectedDistrictId,
);
const areas = getAreas().filter((area) => area.upazilaId === selectedUpazilaId);
const villages = getVillages().filter(
(village) => village.areaId === selectedAreaId,
);This gives you a hierarchy:
Division
↓
District
↓
Upazila
↓
Area
↓
VillageReact Example
import { useState } from "react";
import {
getDivisions,
getDistricts,
getUpazilas,
getAreas,
getVillages,
} from "@olism/bd-geo";
export default function AddressForm() {
const [divisionId, setDivisionId] = useState<number>();
const [districtId, setDistrictId] = useState<number>();
const [upazilaId, setUpazilaId] = useState<number>();
const [areaId, setAreaId] = useState<number>();
const divisions = getDivisions();
const districts = getDistricts().filter(
(district) => district.divisionId === divisionId,
);
const upazilas = getUpazilas().filter(
(upazila) => upazila.districtId === districtId,
);
const areas = getAreas().filter((area) => area.upazilaId === upazilaId);
const villages = getVillages().filter((village) => village.areaId === areaId);
return (
<div>
<select
value={divisionId ?? ""}
onChange={(event) => {
setDivisionId(Number(event.target.value));
setDistrictId(undefined);
setUpazilaId(undefined);
setAreaId(undefined);
}}
>
<option value="">Select Division</option>
{divisions.map((division) => (
<option key={division.id} value={division.id}>
{division.name}
</option>
))}
</select>
<select
value={districtId ?? ""}
onChange={(event) => {
setDistrictId(Number(event.target.value));
setUpazilaId(undefined);
setAreaId(undefined);
}}
>
<option value="">Select District</option>
{districts.map((district) => (
<option key={district.id} value={district.id}>
{district.name}
</option>
))}
</select>
<select
value={upazilaId ?? ""}
onChange={(event) => {
setUpazilaId(Number(event.target.value));
setAreaId(undefined);
}}
>
<option value="">Select Upazila / Thana</option>
{upazilas.map((upazila) => (
<option key={upazila.id} value={upazila.id}>
{upazila.name}
</option>
))}
</select>
<select
value={areaId ?? ""}
onChange={(event) => {
setAreaId(Number(event.target.value));
}}
>
<option value="">Select Area</option>
{areas.map((area) => (
<option key={area.id} value={area.id}>
{area.name}
</option>
))}
</select>
<select>
<option value="">Select Village</option>
{villages.map((village) => (
<option key={village.id} value={village.id}>
{village.name}
</option>
))}
</select>
</div>
);
}Bangla Names
Every geographical entity contains both English and Bangla names.
Example:
{
id: 10,
name: "Dhaka",
nameBn: "ঢাকা",
}Use the English name:
<span>{division.name}</span>Or the Bangla name:
<span>{division.nameBn}</span>This makes the package suitable for applications with both English and Bangla interfaces.
Filtering by Parent
Districts by Division
const districts = getDistricts().filter(
(district) => district.divisionId === divisionId,
);Upazilas by District
const upazilas = getUpazilas().filter(
(upazila) => upazila.districtId === districtId,
);Areas by Upazila
const areas = getAreas().filter((area) => area.upazilaId === upazilaId);Villages by Area
const villages = getVillages().filter((village) => village.areaId === areaId);Filtering Unions and Wards
Because Area contains a type field, you can easily separate unions and wards.
Get all unions
const unions = getAreas().filter((area) => area.type === "union");Get all wards
const wards = getAreas().filter((area) => area.type === "ward");Get unions in an Upazila
const unions = getAreas().filter(
(area) => area.upazilaId === selectedUpazilaId && area.type === "union",
);Get wards in an Upazila
const wards = getAreas().filter(
(area) => area.upazilaId === selectedUpazilaId && area.type === "ward",
);Village Relationship
Villages are linked to areas.
Village
│
└── areaId
│
↓
Area
│
└── type: "union"Example:
const areas = getAreas();
const villages = getVillages();
const village = villages.find((village) => village.id === 1);
const area = areas.find((area) => area.id === village?.areaId);You can verify that the area is a union:
if (area?.type === "union") {
console.log("This village belongs to a union.");
}Using the Package as Database Seed Data
@olism/bd-geo can be used as geographical seed data for applications using:
- Prisma
- TypeORM
- Sequelize
- Drizzle
- NestJS
- Next.js
- Express.js
- Other SQL/NoSQL database systems
The package provides plain JavaScript/TypeScript data, allowing you to transform it into your own database schema.
Recommended Database Structure
A relational database can use the following structure:
divisions
│
└── districts
│
└── upazilas
│
└── areas
│
├── unions
│ └── villages
│
└── wardsExample tables:
divisions
├── id
├── name
├── nameBn
├── latitude
└── longitude
districts
├── id
├── name
├── nameBn
├── divisionId
├── latitude
└── longitude
upazilas
├── id
├── name
├── nameBn
├── districtId
├── type
├── latitude
└── longitude
areas
├── id
├── name
├── nameBn
├── upazilaId
├── type
├── latitude
└── longitude
villages
├── id
├── name
├── nameBn
├── areaId
├── latitude
└── longitudePrisma
Install:
npm install @olism/bd-geoExample prisma/seed.ts:
import { PrismaClient } from "@prisma/client";
import {
getDivisions,
getDistricts,
getUpazilas,
getAreas,
getVillages,
} from "@olism/bd-geo";
const prisma = new PrismaClient();
async function main() {
console.log("Seeding Bangladesh geographical data...");
await prisma.division.createMany({
data: getDivisions(),
});
await prisma.district.createMany({
data: getDistricts(),
});
await prisma.upazila.createMany({
data: getUpazilas(),
});
await prisma.area.createMany({
data: getAreas(),
});
await prisma.village.createMany({
data: getVillages(),
});
console.log("Bangladesh geographical data seeded successfully.");
}
main()
.catch((error) => {
console.error(error);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});Make sure your Prisma model field names match the data provided by the package.
NestJS + TypeORM
Example seed:
import { DataSource } from "typeorm";
import {
getDivisions,
getDistricts,
getUpazilas,
getAreas,
getVillages,
} from "@olism/bd-geo";
import { Division } from "./entities/division.entity";
import { District } from "./entities/district.entity";
import { Upazila } from "./entities/upazila.entity";
import { Area } from "./entities/area.entity";
import { Village } from "./entities/village.entity";
export async function seed(dataSource: DataSource) {
const divisionRepository = dataSource.getRepository(Division);
const districtRepository = dataSource.getRepository(District);
const upazilaRepository = dataSource.getRepository(Upazila);
const areaRepository = dataSource.getRepository(Area);
const villageRepository = dataSource.getRepository(Village);
await divisionRepository.save(getDivisions());
await districtRepository.save(getDistricts());
await upazilaRepository.save(getUpazilas());
await areaRepository.save(getAreas());
await villageRepository.save(getVillages());
}Express.js + Sequelize
The package works independently of your backend framework.
Example:
import {
getDivisions,
getDistricts,
getUpazilas,
getAreas,
getVillages,
} from "@olism/bd-geo";
import { Division } from "./models/division";
import { District } from "./models/district";
import { Upazila } from "./models/upazila";
import { Area } from "./models/area";
import { Village } from "./models/village";
export async function seedDatabase() {
await Division.bulkCreate(getDivisions());
await District.bulkCreate(getDistricts());
await Upazila.bulkCreate(getUpazilas());
await Area.bulkCreate(getAreas());
await Village.bulkCreate(getVillages());
}Next.js + Prisma
You can use the same Prisma seed approach in a Next.js application.
Create:
prisma/
└── seed.tsThen use:
import { PrismaClient } from "@prisma/client";
import {
getDivisions,
getDistricts,
getUpazilas,
getAreas,
getVillages,
} from "@olism/bd-geo";
const prisma = new PrismaClient();
async function main() {
console.log("Seeding Bangladesh geographical data...");
await prisma.division.createMany({
data: getDivisions(),
});
await prisma.district.createMany({
data: getDistricts(),
});
await prisma.upazila.createMany({
data: getUpazilas(),
});
await prisma.area.createMany({
data: getAreas(),
});
await prisma.village.createMany({
data: getVillages(),
});
console.log("Bangladesh geographical data seeded successfully.");
}
main()
.catch((error) => {
console.error(error);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});Important: Preserve Parent-Child Relationships
When inserting geographical data into a relational database, insert the records in hierarchical order:
1. Divisions
↓
2. Districts
↓
3. Upazilas
↓
4. Areas
↓
5. VillagesThis is especially important when your database uses foreign-key constraints.
For example:
await prisma.division.createMany({
data: getDivisions(),
});
await prisma.district.createMany({
data: getDistricts(),
});
await prisma.upazila.createMany({
data: getUpazilas(),
});
await prisma.area.createMany({
data: getAreas(),
});
await prisma.village.createMany({
data: getVillages(),
});The IDs provided by @olism/bd-geo allow parent-child relationships to remain consistent.
Using Only Specific Levels
You don't need to use the entire dataset.
For example, if your application only needs divisions and districts:
import { getDivisions, getDistricts } from "@olism/bd-geo";
const divisions = getDivisions();
const districts = getDistricts();Only upazilas:
import { getUpazilas } from "@olism/bd-geo";
const upazilas = getUpazilas();Only areas:
import { getAreas } from "@olism/bd-geo";
const areas = getAreas();Only villages:
import { getVillages } from "@olism/bd-geo";
const villages = getVillages();Coordinates
Geographical records may contain optional coordinates:
{
latitude?: number;
longitude?: number;
}Example:
{
id: 10,
name: "Dhaka",
nameBn: "ঢাকা",
latitude: 23.8103,
longitude: 90.4125,
}Coordinates can be useful for:
- Maps
- Location markers
- Distance calculations
- Delivery systems
- Location-based search
- Geographic visualizations
Coordinates should be treated as geographical reference data and verified before being used for high-precision applications.
Data Structure
The package source is organized approximately as:
src/
├── types.ts
├── geo.ts
├── index.ts
└── data/
├── divisions.json
├── districts.json
├── upazilas.json
├── areas.json
└── villages.jsonThe JSON files contain the underlying geographical dataset.
The TypeScript API provides convenient access to that data.
Current API
getDivisions();
getDistricts();
getUpazilas();
getAreas();
getVillages();For backward compatibility:
getThanas();getThanas() is deprecated. New applications should use:
getUpazilas();Data Accuracy
Geographical data is an important part of this package.
The dataset may evolve over time as geographical information is added, corrected, or improved.
Before using the data for critical production purposes, verify the relevant information against authoritative Bangladesh government sources where appropriate.
The project aims to maintain consistency in:
- IDs
- English names
- Bangla names
- Parent-child relationships
- Administrative classifications
- Area types
- Geographic coordinates
If you discover incorrect information, please contribute a correction.
Contributing
Contributions are welcome.
You can contribute by:
- Adding missing geographical data
- Correcting English names
- Correcting Bangla names
- Correcting parent-child relationships
- Adding missing villages
- Correcting area types
- Improving coordinates
- Improving tests
- Improving documentation
- Reporting bugs
If you find an issue, please open an issue or submit a pull request in the project repository.
Development
Clone the repository:
git clone https://github.com/mohammad-oliullah/bd-geo.gitEnter the project:
cd bd-geoInstall dependencies:
npm installRun tests:
npm testBuild the package:
npm run buildLicense
MIT License
Copyright (c) 2026 @olism/bd-geo contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
