DEV Community

Lucas Duarte
Lucas Duarte

Posted on

Stop Calling External APIs for Country Data in Laravel — Seed It Into Your Database Instead

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();
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
php artisan w-countries:install
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And if your migrations already ran during deploy and you only need the data:

php artisan w-countries:seed --languages=en,pt,es
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)