Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Indoregion Laravel Package

azishapidin/indoregion

Laravel package for Indonesian administrative region data, offering provinces, regencies, districts, and villages with migrations, Eloquent models, relationships, and seeders. Useful for address forms, shipping, localization, and dependent dropdowns.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and publish:

composer require azishapidin/indoregion
php artisan vendor:publish --provider="AzisHapidin\IndoRegion\IndoRegionServiceProvider"
php artisan migrate

Then seed the region tables. The dataset is large (roughly 34–38 provinces, ~514 regencies/cities, ~7,200 districts, ~83,000 villages), so run it on the CLI with a generous memory limit:

php artisan db:seed --class="AzisHapidin\IndoRegion\Seeders\IndoRegionSeeder"
php artisan tinker --execute="dump(AzisHapidin\IndoRegion\Models\Province::count());"

Look at these first:

  • config/indoregion.php — table names and any publishable settings.
  • src/Models/{Province, Regency, District, Village}.php — relationships run downward (regencies(), districts(), villages()) and backward (province(), regency(), district()).
  • The published migrations — schema is provinces(id, name), regencies(id, province_id, name), districts(id, regency_id, name), villages(id, district_id, name). IDs are BPS codes, not sequential counters.

First real use case: a cascading address picker on a checkout or profile form. Render Province::orderBy('name')->get(), then hit your own endpoint with ?province_id= to fetch regencies, etc., and persist the deepest selected ID (village or district) alongside the resolved codes on the address record.

Implementation Patterns

Cascading dropdown endpoint. A single controller action keyed by level keeps the front end simple:

public function children(Request $request)
{
    $level = $request->enum('level', RegionLevel::class);
    $parent = $request->integer('parent_id');

    $items = match ($level) {
        RegionLevel::Regency  => Regency::where('province_id', $parent)->orderBy('name')->get(['id', 'name']),
        RegionLevel::District => District::where('regency_id', $parent)->orderBy('name')->get(['id', 'name']),
        RegionLevel::Village  => Village::where('district_id', $parent)->orderBy('name')->get(['id', 'name']),
    };

    return response()->json($items);
}

Cache the static tree. Region data barely changes; Cache::rememberForever("regions.regencies.{$provinceId}", ...) is cheap and effective. Bust it in your deploy step after a reseed.

Store both an ID and the code. Your addresses table should keep province_id, regency_id, district_id, village_id for FK integrity, plus the human-readable names snapshot if addresses must remain stable across package updates.

Validate hierarchy, not just existence. exists:villages,id is not enough — assert that the village belongs to the submitted district, which belongs to the regency, which belongs to the province. A single chained query or a whereHas rule handles it.

Eager-load for display. A user list showing full addresses will N+1 badly: User::with('village.district.regency.province'). The four-level chain is a classic performance trap.

Testing. Seed only the subtree you need in fixtures (e.g., Province::insert([...]) for one regency) rather than running the full seeder in test setup — it will dominate your CI time.

Gotchas and Tips

  • The seeder is the slow part, not the migration. Set memory_limit=-1, disable FK checks around truncate-and-reseed, and wrap in a transaction where your driver supports it. On shared hosting, run it via CLI, never a web request.
  • IDs are BPS codes (province 11 = Aceh, regency 11.01, etc.). Never assume they start at 1 or are contiguous. Treat them as opaque identifiers when joining externally (e.g., to government datasets or logistics APIs).
  • "Regency" means both Kabupaten and Kota. Distinguish by the name prefix (Kabupaten ... vs Kota ...), not by a column — the table does not separate them.
  • Data drift is real. Indonesia creates and splits regions periodically; some versions ship 34 provinces, newer ones 38. Pin the package in composer.json and plan a controlled reseed. Addresses referencing removed IDs will break unless you keep the name snapshot or resolve by code.
  • Foreign keys bite on reseed. Your own addresses.village_id FK will block a truncate. Use restrictOnDelete or nullOnDelete deliberately, and script the reseed order (children first, or temporarily disable constraints).
  • No routes shipped by default. Build your own endpoints so you control auth, throttling, and response shape — don't expose the whole tree unauthenticated.
  • Naming is a trap for new team members. The package says Regency where users say Kota/Kabupaten, District for Kecamatan, Village for Desa/Kelurahan. Document the mapping in your domain layer so it doesn't leak into UI labels.
  • Normalize for search. Names contain prefixes; strip Kabupaten /Kota /Kecamatan /Kelurahan /Desa before doing LIKE matching, or users typing "Bandung" will get inconsistent results between the city and the regency.
  • Extension point: if you need extra region metadata (postal codes, coordinates, timezone), add a side table keyed on the BPS code rather than altering the package's tables — a package update that re-publishes migrations will otherwise bite you.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo