If you've ever needed a list of countries in a Laravel app — for a signup form, a shipping calculator, a "select your country" dropdown — you've probably reached for a remote API.
And it usually looks something like this:
$response = Http::get('https://some-country-api.example/countries');
$countries = $response->json();
It works, until it doesn't:
- The API is down and now your signup form is broken
- You hit a rate limit during a traffic spike
- You need country names in Portuguese and Spanish, and the API only returns English
- Your CI pipeline is making real HTTP calls in tests (or worse, mocking them badly)
None of these are exotic edge cases — they're just what happens when a core piece of your app's data lives on someone else's server.
A different approach: put the data in your own database
Laravel Countries takes a simpler approach: instead of calling an API every time you need country data, you seed it once, into your own database, and query it forever after like any other Eloquent model.
| Laravel Countries | Typical remote country API | |
|---|---|---|
| Data lives in | Your own database | A remote server |
| Works offline / in CI | ✅ | ❌ |
| Rate limits | None | Often yes |
| Translations included | 9 languages, out of the box | Usually English only |
| Query with Eloquent | ✅ — it's just a model | Usually a custom HTTP client |
| Extra network calls per request | 0 | 1+ |
Installing it
composer require lwwcas/laravel-countries
php artisan w-countries:install
That single command runs the migrations and seeds countries, regions, and translations. No config files to hand-edit first, no JSON to download and parse yourself.
Querying countries like any other model
Once it's seeded, countries behave exactly like the rest of your app's data:
use Lwwcas\LaravelCountries\Models\Country;
Country::whereIso('BR')->first();
Country::whereIsoAlpha3('BRA')->first();
Country::whereSlug('brasil')->first();
Need a country's name in a specific language? Translations are first-class, not bolted on — the package ships with 9 languages out of the box: Arabic, Dutch, English, German, Italian, Portuguese, Russian, Spanish, and Turkish, with more added as the community contributes reviews.
Production and CI, without the awkward prompts
Laravel normally asks for confirmation before running seeders in production. Laravel Countries handles that automatically:
php artisan w-countries:install --force
And if your migrations already ran during deploy and you only need the data:
php artisan w-countries:seed --languages=en,pt,es
Both commands are safe to drop straight into a deploy script — no hidden prompts, no hanging processes waiting for input that will never come.
Why this matters more than it sounds
Country data feels like a small thing, until it's the piece that makes your signup flow flaky in production, or the reason your test suite needs network access to run. Moving it into your own database removes an entire category of "why did this fail today" — the data is just... there, versioned alongside the rest of your schema, tested in CI the same way as everything else.
Try it out
composer require lwwcas/laravel-countries
php artisan w-countries:install
If it saves you the trouble of building this yourself, a star on the repo genuinely helps other developers find it:
👉 github.com/lwwcas/laravel-countries
Full docs, including production deployment and manual seeder classes, are here: lwwcas.github.io/laravel-countries
Missing a language, or found a translation that needs fixing? Contributions are very welcome — check CONTRIBUTING.md for how translation reviews work.
Top comments (0)