Laravel package for Indonesian address data with postal codes — downloaded fresh from Pos Indonesia.
- Postal code lookup — Query villages by postal code with full address hierarchy
- Fresh data — Downloads directly from Pos Indonesia, not static dumps
- Idempotent seeders — Safe to run multiple times without duplicates
- Hierarchical parsing — Province → Regency → District → Village with name normalization
- Custom models — Extend default models or use your own
- Laravel 11, 12, 13 — Modern PHP 8.3+
composer require ajangsupardi/laravel-postcode-idphp artisan vendor:publish --tag=postcode-configphp artisan vendor:publish --tag=postcode-migrationsNote: Migrations are automatically loaded by the service provider, so publishing is only needed if you want to modify the table structure.
php artisan postcode:downloadThis command will download all postcode data from Pos Indonesia and save it as a CSV file.
php artisan migrate
php artisan postcode:seedOr add it to your DatabaseSeeder.php:
use Ajangsupardi\PostcodeId\Database\Seeders\PostcodeSeeder;
public function run(): void
{
$this->call([
PostcodeSeeder::class,
]);
}If you want to combine download and seed in a single step, you can call the download command before the seeder:
use Illuminate\Support\Facades\Artisan;
$storagePath = config('postcode.storage_path');
if (! file_exists($storagePath.'/kodepos.csv')) {
Artisan::call('postcode:download');
}The main feature — find any Indonesian address by postal code:
use Ajangsupardi\PostcodeId\Models\Village;
// Village by postal code
$village = Village::where('postal_code', '60111')->first();
// With full address hierarchy
$village = Village::with('district.regency.province')
->where('postal_code', '60111')
->first();
// Result: Gubeng → Kota Surabaya → Jawa Timur// Search by village name
$villages = Village::where('name', 'LIKE', '%Gubeng%')
->with('district.regency')
->get();This package creates 4 tables:
| Table | Description |
|---|---|
provinces |
Province data (id, name, code) |
regencies |
Regency/city data (id, province_id, name) |
districts |
District/sub-district data (id, regency_id, name) |
villages |
Village data (id, district_id, name, postal_code) |
Edit config/postcode.php:
return [
// CSV file storage path
'storage_path' => storage_path('app/postcode'),
// Database table prefix (null = no prefix)
'table_prefix' => null,
// Custom models
'models' => [
'province' => Ajangsupardi\PostcodeId\Models\Province::class,
'regency' => Ajangsupardi\PostcodeId\Models\Regency::class,
'district' => Ajangsupardi\PostcodeId\Models\District::class,
'village' => Ajangsupardi\PostcodeId\Models\Village::class,
],
// HTTP client settings
'http' => [
'timeout' => 60,
'connect_timeout' => 10,
'retry' => 3,
'retry_delay' => 1000,
'user_agent' => 'Mozilla/5.0 (compatible; LaravelPostcodeId/1.0)',
],
];You can extend the default models to add columns or relationships:
namespace App\Models;
use Ajangsupardi\PostcodeId\Models\Province as BaseProvince;
class Province extends BaseProvince
{
protected $fillable = ['name', 'code', 'your_custom_field'];
// Add custom relationships or methods
}Then update the configuration:
'models' => [
'province' => App\Models\Province::class,
],If you want to use a prefix for your tables:
'table_prefix' => 'postcode_',This will create tables: postcode_provinces, postcode_regencies, postcode_districts, postcode_villages.
use Ajangsupardi\PostcodeId\Models\Province;
use Ajangsupardi\PostcodeId\Models\Village;
// Get all provinces
$provinces = Province::all();
// Get regencies in East Java
$regencies = Province::where('name', 'Jawa Timur')
->first()
->regencies;
// Find a village by postal code
$village = Village::where('postal_code', '60111')->first();
// Get full address hierarchy from village to province
$village = Village::with('district.regency.province')
->where('postal_code', '60111')
->first();- PHP ^8.3
- Laravel ^11.0 / ^12.0 / ^13.0
- Added
postcode:seedartisan command to fix shell escaping bug on Linux
- Initial release — download, parse, and seed Indonesian address data with postal codes
MIT License. See LICENSE for more information.