PHPackages                             madebyclowd/laravel-nusantara - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. madebyclowd/laravel-nusantara

ActiveLibrary[Database &amp; ORM](/categories/database)

madebyclowd/laravel-nusantara
=============================

Indonesia administrative regions database (provinces, regencies, districts, villages) for Laravel.

v1.1.9(1mo ago)031↓85.7%MITPHPPHP ^8.2CI passing

Since Jun 5Pushed 1mo agoCompare

[ Source](https://github.com/madebyclowd/laravel-nusantara)[ Packagist](https://packagist.org/packages/madebyclowd/laravel-nusantara)[ RSS](/packages/madebyclowd-laravel-nusantara/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (12)Versions (13)Used By (0)

Laravel Nusantara
=================

[](#laravel-nusantara)

[![Latest Version on Packagist](https://camo.githubusercontent.com/b5bc61b1cc6f227c405f426292b2e9c599491926f3d05b33fb679b8e165f6ed9/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d6164656279636c6f77642f6c61726176656c2d6e7573616e746172612e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/madebyclowd/laravel-nusantara)[![GitHub Tests Action Status](https://camo.githubusercontent.com/552bec25d91c2f01cdb4609b7465c77d05becd4690f7ce5f3fd0fbaba5700e5b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d6164656279636c6f77642f6c61726176656c2d6e7573616e746172612f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/madebyclowd/laravel-nusantara/actions)[![Total Downloads](https://camo.githubusercontent.com/4a3eb9b52d6b5b8e27c9aeed30f094d7b187a11cc88035c4f8b28fd013ebed51/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d6164656279636c6f77642f6c61726176656c2d6e7573616e746172612e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/madebyclowd/laravel-nusantara)[![License](https://camo.githubusercontent.com/8ff0100375644e9d0a93cca088a1172338d271b59f8cc39418199e3c2ff4c3f7/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6d6164656279636c6f77642f6c61726176656c2d6e7573616e746172612e7376673f7374796c653d666c61742d737175617265)](https://github.com/madebyclowd/laravel-nusantara/blob/main/LICENSE)

A highly customizable, enterprise-ready, and developer-friendly Laravel package for Indonesia's administrative regions database (Provinces, Regencies, Districts, and Villages). Compiled according to **Kepmendagri No 300.2.2-2138 Year 2025**.

---

⚡ Key Features
--------------

[](#-key-features)

- **Complete Schema Freedom**: Use SQLite, PostgreSQL, MySQL, SQL Server, or any custom connection.
- **Custom Table &amp; Column Names**: Rename any default table or column to match your corporate database schema guidelines.
- **Column Exclusion / Toggles**: Disable columns you don't need (e.g. `elevation`, `timezone`, `area`, `population`) to save storage space.
- **Dynamic Attribute Accessor Mapping**: Models use a transparent mapping layer. You can call `$province->name` in your codebase even if it is saved as `nama_provinsi` in the database.
- **Tag-Safe Query Caching**: Minimizes database overhead on repetitive queries using Laravel's caching layer with automatic tag/key prefixes.
- **Cascading Eloquent Relations**: Provides relationships from Province to Regency, District, and Villages (with optimized join methods for deep traversals).
- **Ready-to-Use JSON REST API**: Built-in endpoints protected by middleware and rate limiters for checkout/registration widgets.
- **Low-Memory Seeder**: Streams gzipped CSV data line-by-line, keeping memory consumption under 3MB during the seed.
- **On-Demand Geographic Boundaries**: Keep your package footprint small by downloading high-resolution GIS boundary coordinates only if and when you need them.
- **AI-Agent Ready**: Automatically registers its developer instructions with **Laravel Boost** (`SKILL.md`) to help coding assistants query the dataset correctly.

---

🚀 Requirements
--------------

[](#-requirements)

- **PHP**: `^8.2`
- **Laravel Framework**: `^10.0`, `^11.0`, `^12.0`, or `^13.0`

---

📦 Installation
--------------

[](#-installation)

Install the package via Composer:

```
composer require madebyclowd/laravel-nusantara
```

### Option A: Interactive Setup (Recommended)

[](#option-a-interactive-setup-recommended)

Run the interactive installer wizard which publishes configuration, executes database migrations, and seeds regional data:

```
php artisan nusantara:install
```

### Option B: Manual Setup

[](#option-b-manual-setup)

If you prefer custom automation or wish to review steps individually:

1. **Publish the configuration file:**

    ```
    php artisan vendor:publish --tag=nusantara-config
    ```
2. **Publish and customize migrations (Optional):***(Note: By default, the package loads migrations automatically. If you want to customize migration files manually, set `'load_migrations' => false` in `config/nusantara.php` first).*

    ```
    php artisan vendor:publish --tag=nusantara-migrations
    ```
3. **Run database migrations:**

    ```
    php artisan migrate
    ```
4. **Seed database:**

    ```
    php artisan db:seed --class="MadeByClowd\Nusantara\Seeders\NusantaraCoreSeeder"
    ```

---

🗺️ Geographic Boundaries (GIS)
------------------------------

[](#️-geographic-boundaries-gis)

If your application requires geographic boundary shapes (polygons), you can download and seed them on-demand:

1. Enable the `boundary` column for the desired levels (provinces, regencies, districts, or villages) in `config/nusantara.php`: ```
    'columns' => [
        'provinces' => [
            // ...
            'boundary' => ['name' => 'boundary', 'enabled' => true],
        ],
    ]
    ```
2. Run the boundary download Artisan command: ```
    php artisan nusantara:download-boundaries
    ```

*(Note: The command will download, verify checksums, and seed the high-resolution GIS coordinates into your database automatically).*

---

⚙️ Configuration
----------------

[](#️-configuration)

The configuration is located at `config/nusantara.php`. Below is a detailed breakdown of what you can customize:

```
return [
    // Automatically load migrations from the package
    'load_migrations' => true,

    // Database connection to use (null defaults to app connection)
    'connection' => null,

    // Custom table names
    'tables' => [
        'provinces' => 'provinces',
        'regencies' => 'regencies',
        'districts' => 'districts',
        'villages'  => 'villages',
    ],

    // Enable or disable foreign key constraints
    'enable_foreign_keys' => true,

    // Map Eloquent models. Replace default classes with your own extensions
    'models' => [
        'province' => \MadeByClowd\Nusantara\Models\Province::class,
        'regency'  => \MadeByClowd\Nusantara\Models\Regency::class,
        'district' => \MadeByClowd\Nusantara\Models\District::class,
        'village'  => \MadeByClowd\Nusantara\Models\Village::class,
    ],

    // Query Caching Configuration
    'cache' => [
        'enabled' => true,
        'ttl'     => 86400, // 24 hours
        'prefix'  => 'nusantara',
    ],

    // REST API configuration
    'api' => [
        'enabled'    => false, // Set to true to expose JSON endpoints
        'prefix'     => 'api/nusantara',
        'middleware' => ['api', 'throttle:60,1'],
    ],

    // Columns configurations. Toggle 'enabled' or change the DB 'name'
    'columns' => [
        'provinces' => [
            'id'          => ['name' => 'id', 'enabled' => true],
            'name'        => ['name' => 'name', 'enabled' => true], // e.g. rename to 'nama'
            'capital'     => ['name' => 'capital', 'enabled' => true],
            'latitude'    => ['name' => 'latitude', 'enabled' => true],
            'longitude'   => ['name' => 'longitude', 'enabled' => true],
            'elevation'   => ['name' => 'elevation', 'enabled' => true],
            'timezone'    => ['name' => 'timezone', 'enabled' => true],
            'area'        => ['name' => 'area', 'enabled' => true],
            'population'  => ['name' => 'population', 'enabled' => true],
            'boundary'    => ['name' => 'boundary', 'enabled' => false], // GIS Boundary Coordinates
        ],
        // ... (regencies, districts, villages keys follow the same structure)
    ],
];
```

Important

**Referential Integrity Constraints**Primary keys and foreign keys (`id`, `province_id`, `regency_id`, `district_id`) must remain enabled (`'enabled' => true`) in the configuration to preserve database relationships. The package will validate this and fail fast with an exception during migrations if misconfigured.

---

🏛️ Unified Facade (`Nusantara`)
-------------------------------

[](#️-unified-facade-nusantara)

The `Nusantara` facade is the recommended way to query administrative regions, as it automatically implements caching under the hood:

```
use MadeByClowd\Nusantara\Facades\Nusantara;

// 1. Fetch Collection of all Provinces
$provinces = Nusantara::provinces();

// 2. Fetch specific Province by ID
$province = Nusantara::findProvince('11'); // returns Province model or null

// 3. Fetch Collection of Regencies of a Province
$regencies = Nusantara::regenciesOf('11'); // Province ID '11'

// 4. Fetch specific Regency by ID
$regency = Nusantara::findRegency('1101'); // returns Regency model or null

// 5. Fetch Collection of Districts of a Regency
$districts = Nusantara::districtsOf('1101'); // Regency ID '1101'

// 6. Fetch specific District by ID
$district = Nusantara::findDistrict('110101'); // returns District model or null

// 7. Fetch Collection of Villages of a District
$villages = Nusantara::villagesOf('110101'); // District ID '110101'

// 8. Fetch specific Village by ID
$village = Nusantara::findVillage('1101012001'); // returns Village model or null

// 9. Search regions dynamically across all administrative levels
// (Requires a query string length >= 2; matches using SQL LIKE %query%)
$results = Nusantara::search('Bakongan');
/*
Returns array:
[
    'provinces' => [...],
    'regencies' => [...],
    'districts' => [...],
    'villages'  => [...]
]
*/

// 10. Clear cached regional queries manually
Nusantara::clearCache();
```

---

📂 Eloquent Models &amp; Relations
---------------------------------

[](#-eloquent-models--relations)

Laravel Nusantara provides dedicated Eloquent models (`Province`, `Regency`, `District`, `Village`) that handle table and foreign key resolution dynamically based on configuration.

### Model Relationships

[](#model-relationships)

All relations resolve keys and table names dynamically:

```
use MadeByClowd\Nusantara\Models\Province;
use MadeByClowd\Nusantara\Models\Regency;
use MadeByClowd\Nusantara\Models\District;

$province = Province::find('11');

// Province -> Regencies (HasMany)
$regencies = $province->regencies;

// Province -> Districts (HasManyThrough)
$districts = $province->districts;

// Province -> Villages (Custom optimized Join query builder)
$villages = $province->villages()->get();

// Regency -> Province (BelongsTo)
$province = $regencies->first()->province;

// Regency -> Districts (HasMany)
$districts = $regencies->first()->districts;

// Regency -> Villages (HasManyThrough)
$villages = $regencies->first()->villages;

// District -> Regency (BelongsTo)
$regency = $districts->first()->regency;

// District -> Villages (HasMany)
$villages = $districts->first()->villages;

// Village -> District (BelongsTo)
$district = $villages->first()->district;
```

### Transparent Schema Mapping (Magic Properties)

[](#transparent-schema-mapping-magic-properties)

The models use the `HasDynamicNusantaraFields` trait. If you rename columns in your configuration (for example, renaming `'name'` to `'nama_provinsi'`), you can still access the properties using their standard logical names:

```
// If in config/nusantara.php you configured: 'name' => ['name' => 'nama_provinsi']
$province = Province::find('11');

echo $province->name;          // Outputs: "Aceh" (Intercepted and mapped dynamically)
echo $province->nama_provinsi; // Outputs: "Aceh" (Direct DB attribute access also works)
```

---

🌐 Optional REST API Endpoints
-----------------------------

[](#-optional-rest-api-endpoints)

If you are building dynamic frontend UI components (such as checkout dropdowns or select forms), you can expose ready-to-use JSON API endpoints by setting `'api.enabled' => true` in your configuration.

All request parameters are strictly validated:

### 1. Get Provinces

[](#1-get-provinces)

- **Endpoint**: `GET /api/nusantara/provinces`
- **Response**: JSON array of Province records.

### 2. Get Regencies of a Province

[](#2-get-regencies-of-a-province)

- **Endpoint**: `GET /api/nusantara/regencies?province_id={id}`
- **Validation**: `province_id` is required, string, exactly 2 characters.
- **Response**: JSON array of Regency records.

### 3. Get Districts of a Regency

[](#3-get-districts-of-a-regency)

- **Endpoint**: `GET /api/nusantara/districts?regency_id={id}`
- **Validation**: `regency_id` is required, string, exactly 4 characters.
- **Response**: JSON array of District records.

### 4. Get Villages of a District

[](#4-get-villages-of-a-district)

- **Endpoint**: `GET /api/nusantara/villages?district_id={id}`
- **Validation**: `district_id` is required, string, exactly 6 characters.
- **Response**: JSON array of Village records.

### 5. Search Regions

[](#5-search-regions)

- **Endpoint**: `GET /api/nusantara/search?q={query}`
- **Validation**: `q` is required, string, between 2 and 50 characters.
- **Response**: JSON object with matching results grouped by level: ```
    {
      "provinces": [],
      "regencies": [],
      "districts": [],
      "villages": []
    }
    ```

---

🤖 AI Agent Integration (Laravel Boost)
--------------------------------------

[](#-ai-agent-integration-laravel-boost)

This package features native integration with **Laravel Boost**. When you install or update the package in an application with Laravel Boost configured, the package automatically publishes an AI agent skill file (`SKILL.md`) to the host project at `.github/skills/laravel-nusantara/SKILL.md` or `.ai/skills/laravel-nusantara/SKILL.md`.

This ensures that any AI coding assistant used by developers in their host application understands:

1. Dynamic attribute mappings and configuration.
2. The dynamic database columns/table schema.
3. Best practices to avoid hardcoding table names in custom queries.

---

🧪 Testing
---------

[](#-testing)

To run the package test suite locally:

```
composer install
vendor/bin/phpunit
```

---

🤝 Credits
---------

[](#-credits)

- Special thanks to [cahyadsn](https://github.com/cahyadsn) for curating and providing the raw Indonesia administrative data used as the source for this package's dataset.

---

📄 License
---------

[](#-license)

The MIT License (MIT). Please see [LICENSE](LICENSE) for more information.

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance91

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

12

Last Release

42d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/408d62b900f14d9f25e46c92b0c3faff6822c849b20cfcefc0ac7c0b0b420530?d=identicon)[wawanwidiantara](/maintainers/wawanwidiantara)

---

Top Contributors

[![wawanwidiantara](https://avatars.githubusercontent.com/u/108401056?v=4)](https://github.com/wawanwidiantara "wawanwidiantara (28 commits)")

---

Tags

administrative-regionsdistrictsgeojsonindonesialaravelprovincesregenciesseedervillageswilayahlaraveldatabaseseederindonesiawilayahregionsprovincesdistrictsregenciesvillagesadministrative

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/madebyclowd-laravel-nusantara/health.svg)

```
[![Health](https://phpackages.com/badges/madebyclowd-laravel-nusantara/health.svg)](https://phpackages.com/packages/madebyclowd-laravel-nusantara)
```

###  Alternatives

[mongodb/laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel

7.1k8.4M98](/packages/mongodb-laravel-mongodb)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[yajra/laravel-oci8

Oracle DB driver for Laravel via OCI8

8793.2M25](/packages/yajra-laravel-oci8)[glushkovds/phpclickhouse-laravel

Adapter of the most popular library https://github.com/smi2/phpClickHouse to Laravel

2051.5M2](/packages/glushkovds-phpclickhouse-laravel)[aimeos/laravel-nestedset

Nested Set Model for Laravel

3714.4k7](/packages/aimeos-laravel-nestedset)[itpathsolutions/dbstan

Database Standardization and Analysis Tool for Laravel

463.0k](/packages/itpathsolutions-dbstan)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
