Skip to content

Regions

Regions follow Kepmendagri 300.2.2-2138/2025 as amended by 300.2.2-2430/2025. Each level adds one segment to the code:

  1. Province province31DKI Jakarta38
  2. Regency or city regency31.71Jakarta Pusat514
  3. District district31.71.01Gambir7,285
  4. Village village31.71.01.1001Gambir83,762
  • GambirDistrict31.71.01Daerah Khusus Ibukota Jakarta › Kota Administrasi Jakarta Pusat
  • GambirVillage31.71.01.1001Daerah Khusus Ibukota Jakarta › Kota Administrasi Jakarta Pusat › Gambir
  • GambiranDistrict35.10.07Jawa Timur › Kabupaten Banyuwangi
  • Gambir BaruVillage12.09.20.1012Sumatera Utara › Kabupaten Asahan › Kota Kisaran Timur
  • GambirmanisVillage33.12.01.2004Jawa Tengah › Kabupaten Wonogiri › Pracimantoro
  • GambiranomVillage33.12.07.2006Jawa Tengah › Kabupaten Wonogiri › Baturetno

Runs in your browser.

Codes may be written with or without dots, spaces or hyphens (3171, 31.71, 31 71).

Go TypeScript Returns
region.Get(code) region.get(code) One region with the current code
region.Resolve(code) region.resolve(code) Like Get, but follows codes renumbered by the 2012 Kalimantan Utara and 2022 Papua splits
region.Children(code) region.children(code) Direct children, "" lists the provinces
region.Search(q, opts) region.search(q, opts) Regions whose name matches q, best match first
region.ByPlate(code) region.byPlate(code) Regencies registered under a plate code such as DR
region.ByAreaCode(code) region.byAreaCode(code) Province or regencies behind a fixed-line area code
region.FromNIK(nik) region.fromNik(nik) Province, regency and district names for a NIK

In TypeScript every function is async: district and village data are split into one chunk per province and load only when needed. The index of provinces, regencies, aliases, plates and area codes is under 16 KB gzip. In Go, data loads once on first use (about 10 ms).

The per-province chunks rely on dynamic import(). Vite, webpack, Rollup and esbuild with splitting: true emit them as separate files. A bundler that inlines dynamic imports puts every province into one file (about 500 KB gzip), so enable code splitting for browser builds.

Go SearchOptions TypeScript Meaning
Level level Only one level: province, regency, district, village
Within within Only descendants of this code
Limit limit 1 to 100, default 10

Matching ignores case and the Kabupaten/Kota prefix. Exact names rank first, then prefixes, then word starts, then any substring. Queries are limited to 256 characters.

Searching districts or villages without within reads every province. In a browser, pass within to load a single province.

Field Notes
province Always present
regency Present when the regency still exists
district Present when the district still exists
historical true when the NIK uses a code from before a split, names are current

length, charset, unknown (well-formed code that does not exist), options.

package main
import (
"fmt"
"github.com/haikalmumtaz233/nusaindex/region"
)
func main() {
regency, err := region.Get("31.71")
if err == nil {
fmt.Println(regency.Name, regency.Level, regency.ParentCode)
}
districts, err := region.Children("31.71")
if err == nil {
fmt.Println(len(districts), districts[0].Name)
}
found, err := region.Search("gambir", region.SearchOptions{Level: region.LevelDistrict, Limit: 2})
if err == nil {
for _, r := range found {
fmt.Println(r.Code, r.Name)
}
}
current, err := region.Resolve("91.04")
if err == nil {
fmt.Println(current.Code, current.Name)
}
byPlate, err := region.ByPlate("DR")
if err == nil {
fmt.Println(len(byPlate), byPlate[0].Name)
}
byArea, err := region.ByAreaCode("0274")
if err == nil {
fmt.Println(byArea[0].Code, byArea[0].Name)
}
place, err := region.FromNIK("7502010706599583")
if err == nil {
fmt.Println(place.Province.Name, place.Regency.Name, place.District.Name, place.Historical)
}
}
Output
Kota Administrasi Jakarta Pusat regency 31
8 Gambir
31.71.01 Gambir
35.10.07 Gambiran
94.01 Kabupaten Nabire
5 Kabupaten Lombok Barat
34.71 Kota Yogyakarta
Gorontalo Kabupaten Boalemo Paguyaman false