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

Laravel Countries Laravel Package

lwwcas/laravel-countries

Eloquent-first country database for Laravel. Every ISO 3166 Alpha-2, Alpha-3 and numeric code, international phone code, currency, SVG and emoji flag, GeoJSON border and translation is a native Eloquent relationship—one Country:: call away, with no external API needed.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and seed in one shot:

composer require lwwcas/laravel-countries
php artisan w-countries:install

Before running the installer, decide your language set — it's the one irreversible-ish choice you make on day one. Seeding all nine languages when the app only serves English and Portuguese just makes every translation join heavier:

php artisan w-countries:install --languages=en,pt

Where to look first, in this order:

  1. Lwwcas\LaravelCountries\Models\Country — the model is the API. Read its scopes and accessors before writing any query.
  2. The Method Listing docs — this is where the real surface area lives; the README is a teaser.
  3. The package migrations — you need to know the column names and whether iso, iso_alpha3, iso_numeric are indexed in your DB before you build FKs on them.
  4. config/ after publishing — translation/table settings and any model binding hooks.

First real use case: a countries dropdown on a registration or address form that persists a country_id, not a raw two-letter string. Do the lookup by ISO only on the boundary (Country::whereIso('BR')->firstOrFail()->id); store the FK, join later.

Production/CI:

php artisan w-countries:install --force
# or, when migrations already ran during deploy:
php artisan w-countries:seed --languages=en,pt

Run w-countries:seed --show-commands once to see the underlying db:seed invocations — you'll want those in your deploy script rather than shelling out to an interactive command.

Implementation Patterns

Foreign keys over string codes. The package is valuable precisely because countries is a real table you can relate to. Add country_id to users, addresses, orders, pricing_tiers, and relate normally:

Schema::table('addresses', fn (Blueprint $t) =>
    $t->foreignId('country_id')->constrained('countries'));
class Address extends Model {
    public function country(): BelongsTo { return $this->belongsTo(Country::class); }
}

Keep a country_code string column only if you need historical audit data that must survive a reseed.

Dropdowns and list endpoints. Pull only what you render, and order by the translated name, not the raw column:

Country::query()
    ->with('translation')            // avoid N+1 on names
    ->get()
    ->map(fn ($c) => ['id' => $c->id, 'name' => $c->name, 'iso' => $c->iso]);

If your list is hot, cache it keyed on locale + language set:

Cache::rememberForever("countries.options.{$locale}", fn () => ...);

Validation rules. Phone number validation is the highest-value integration: prefix checking against wherePhoneCode('+55') catches obvious mismatches before you reach a real phone library. Remember dialing codes are shared (+1 covers US, CA, and more) — use it as a soft check, not an identity check.

Currency and region segmentation. whereCurrency, GDP, and region relationships are good for feature gating, tax/price tables, and analytics grouping. Seed a regions lookup and relate your own models to it if you segment by continent.

Flags in Blade. flag_emoji for lists and toggles, flag_svg only where you need crisp rendering. Don't loop flag_svg over 250 rows — that's megabytes of markup in the response.

GeoJSON. Treat geojson as a server-side column. Use it for generating map tiles, choropleths, or spatial joins; ship latitude/longitude to the frontend and fetch borders per-country on demand.

Localization. Wrap country lookups in a small service that resolves the current locale against your installed language set and falls back explicitly. This is the seam where you'd swap the package later.

Gotchas and Tips

  • Version matters a lot. The 3.x changelog shows Laravel 9/10 support; 4.13.x targets L11–L13. Pin a version and read release/4.13.1.md before upgrading — migration path casing and dependency bumps have broken things before.
  • Migration ordering. Changelog 3.1.0 explicitly reordered migration execution. If your own migration adds country_id, verify the package migration ran first in a fresh migrate:fresh — otherwise FK creation fails intermittently depending on discovery order.
  • Seeding is not free-form. --force skips prompts; it does not make an unguarded db:seed safe. Never run the package seeder implicitly in a db:seed chain in production without the language flag, or you'll reintroduce languages you deliberately dropped.
  • Adding/removing languages later is a deploy step, not a code change. Every environment needs the same w-countries:seed --languages=... run. Removing a language deletes translation rows — audit anything that referenced translated names before dropping.
  • SELECT * is expensive here. GeoJSON, SVG flags, and translation joins make toArray() on a full collection surprisingly large. Scope columns for lists and API resources.
  • Don't select() your way out of accessors. Translatable/accessor-backed attributes (name, flag_colors) may depend on columns or relations you excluded. Verify before trimming.
  • Unit traps. GDP is in billions USD per the README, and slug lookups are locale-sensitive (brasil vs brazil). Write these assumptions into tests, not comments.
  • Cache invalidation on reseed. If you cache lookups forever, your deploy must flush the relevant keys after w-countries:seed. A versioned cache key (countries.v{schema}.{locale}) is cheaper than remembering.
  • Testing. Seeding 250 countries per test is the main performance hazard. Use a minimal language set in phpunit.xml, seed once in a base TestCase where the DB survives, or seed only the handful of countries a test needs via direct model creation.
  • Extension points. Don't edit vendor migrations or the model. Publish the config, and if you need extra per-country app data (shipping zones, VAT rates), add your own table keyed on countries.id rather than widening theirs.
  • Data corrections happen. The changelog shows removed countries (AN), duplicate fixes (CY), and added entries (PH). Pin, watch releases, and plan reseeds — a "static" seed is only static until the next tag.
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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
mrnewport/laravel-repo
pdustdar/elasticsearch
rlacerda83/lumem-microservice-shipment
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation