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

Countries Laravel Package

mledoze/countries

PHP library of world country data: names, ISO codes, capitals, regions, currencies, languages, borders, area, population, and translations. Ships as JSON, CSV, XML, YAML, and PHP arrays for easy import.

Deep Wiki
Context7

Technical Evaluation

Architecture fit. This is not a PHP library — it is a data artifact (JSON/YAML/CSV/XML flat files) with a thin Packagist wrapper. There is no service provider, no config contract, no facade, no exception hierarchy, no API surface to design against. Architecturally it fits in exactly one place: as a build-time seed source for a normalized countries lookup table (plus country_translations, currencies, optionally subdivisions), consumed behind a first-party CountryRepository interface. It does not fit as a runtime dependency you inject, mock, or version-pin at the application layer. If a team treats it as a live dependency (reading vendor/mledoze/countries/dist/countries.json at request time or in a scheduled job), they have created an undeclared coupling to a vendor's internal file layout that upstream has never committed to stabilizing.

Integration feasibility. High mechanically, low strategically. Ingest is a one-to-two-day job: an artisan command that reads the JSON, validates the expected keys, and upserts into Eloquent models inside a transaction. The data volume (~250 country records, a few thousand subdivisions, a few hundred translations) is small enough to seed synchronously in a deploy hook and cache entirely in memory or Redis. There are no framework or PHP-version constraints to reconcile, which is genuinely the package's strongest technical property — it cannot conflict with anything. The friction is that "integration" here means we write the integration, and we own it forever.

Technical risk. Three items, ordered by severity:

  1. License (ODbL-1.0) — the gating risk. ODbL is a share-alike license on databases, not code. If our usage constitutes a "derivative database" that we make publicly available, we may be obligated to offer that derivative under ODbL. The "produced work" carve-out likely covers rendering country names in a UI, but "likely" is not a position to ship a commercial SaaS on. Every other risk here is recoverable in a sprint; a licensing defect discovered post-launch forces a re-source under time pressure across every table, validation rule, and stored address record.
  2. Unversioned data contract. Releases are tagged but the shape of the data is not semver'd. A field can be renamed, a nested object restructured, or a translation dropped between tags with no migration note. Any importer we build is implicitly pinned to a commit, not a version.
  3. Politically and operationally sensitive content. Disputed territories, naming conventions (Türkiye, North Macedonia, Eswatini), and translation quality are editorial decisions made by upstream contributors, not by us. These surface directly in user-facing address forms, shipping logic, and tax flows.

Key questions for the team before proceeding:

  • Legal: does embedding a country lookup table in our application database constitute a derivative database under ODbL, and does our distribution model (SaaS? on-prem? mobile bundle?) trigger share-alike?
  • Why this over league/iso3166 (MIT) and symfony/intl (MIT), which together cover ISO 3166-1 codes, English names, and ICU-localized display names behind a maintained PHP API? What does mledoze/countries give us that those do not — subdivisions, demonyms, lat/lng, border adjacency, TLD?
  • Who owns diff review when upstream data changes, and on what cadence?
  • Do we need disputed-territory representation and non-ISO entities, or is strict ISO 3166 sufficient?
  • Do we need translations, or only English display names plus our own localization layer?

The opportunity score of 4.89 reflects reality: this is a commodity dataset with near-zero differentiation and a licensing drag. The correct framing is "buy vs. build vs. borrow a seed file," not "adopt a package."

Integration Approach

Stack fit. Laravel 10/11 on PHP 8.1+ — fully compatible, because there is nothing to be incompatible with. Target design:

  • countries table: id, iso2 (unique, indexed), iso3, numeric_code, name_common, name_official, region, subregion, capital, currency_codes (JSON), calling_code, tld, lat, lng, area_km2, independent (bool).
  • country_translations table keyed on (country_id, locale).
  • CountryRepository contract bound in a CountryServiceProvider, backed by a cache-aside read (Cache::rememberForever with a version key bumped on deploy).
  • A CountryCode validation rule delegating to the repository, plus a Blade/Blade-component select so forms stop hand-rolling country dropdowns.

This is the pattern that makes the underlying source swappable. If legal kills ODbL, we re-point the importer at a different dataset and change nothing else — that optionality is the whole design goal.

Migration path (phased, legal-gated):

  • Phase 0 — Legal review. Explicit go/no-go on ODbL. Nothing else starts until this clears. Budget one to two weeks of counsel time.
  • Phase 1 — One-shot import. Artisan command + idempotent seeder. Normalize into our own schema; commit the normalized seed output, not the vendor directory.
  • Phase 2 — Drop the runtime dependency. Remove the composer requirement. The application now has no knowledge of mledoze/countries; it knows only our tables and our repository.
  • Phase 3 — Update pipeline. A scheduled job that fetches the upstream tag, diffs against our committed snapshot, and opens a PR with a human-readable change summary for review. Never auto-merge; country data changes are editorial decisions.

Compatibility. No PHP version constraints, no Laravel constraints, no transitive dependency graph, no autoloader conflicts. If we vendor only the JSON, the dependency graph impact is literally zero. If we keep the composer package, we inherit its autoload map and nothing else.

Sequencing. Legal → schema → importer → repository + cache → validation rule + UI component → update pipeline. Roughly 1.5 sprints for one mid-level engineer, with the entire schedule contingent on Phase 0. Do not run Phase 0 in parallel with Phase 1; the cost of a false start here is a full teardown of seeded reference data and every foreign key pointing at it.

Fallback plan. If legal does not clear ODbL, the MIT path is league/iso3166 for codes and names plus symfony/intl for localized display names. Coverage is narrower (no subdivisions, demonyms, or border adjacency), so confirm the product actually needs those fields before assuming the fallback is a downgrade.

Operational Impact

Maintenance. The cost shifts entirely to us after import. Upstream shows recent activity (last release Feb 2025) but no disciplined changelog or data-shape versioning — updates must be reviewed as raw diffs. Realistic budget: ~1 engineer-day per quarter for diff review plus a short product/compliance pass on any politically sensitive naming change. That is the recurring cost, and it is small but permanent.

Support. No vendor, no SLA, no support channel beyond GitHub issues. Acceptable for a commodity reference dataset — but it means there is no one to escalate to when a country rename breaks an address form on a Friday.

Scaling. Non-issue. ~250 rows, seeded once, cached in Redis or a static array. Reads are sub-millisecond and effectively free. This package will never appear on a capacity or latency dashboard. Do not let a scaling concern — real or imagined — enter the decision.

Failure modes, ranked:

  1. License contamination discovered post-launch. Highest impact, lowest probability if Phase 0 is done properly. Mitigation: Phase 0, plus the repository abstraction that makes re-sourcing a config change rather than a refactor.
  2. Stale data in transactional flows. A renamed country or changed currency surfacing in shipping addresses, tax calculation, or KYC. Mitigation: quarterly review cadence, and a source_version column on the table so we can prove what snapshot is live.
  3. Silent importer breakage from schema drift. Upstream renames a key; the importer writes nulls instead of failing. Mitigation: strict schema assertions in the importer and a post-import row/field count check that fails the deploy.
  4. Disputed-territory and naming fallout. Regional user complaints, app store review friction, or regulatory questions. Mitigation: product sign-off on a documented representation policy, not an engineer's judgment call at 5pm.
  5. Over-coupling to vendor file paths. Mitigation: already handled by Phase 2.

Ramp-up. Engineering ramp is roughly half a day — it is JSON in a file, and any Laravel developer can seed it. Infrastructure ramp is zero. The real ramp-up is legal and product-organizational, and that is where a TPM should spend their attention: getting counsel to render an ODbL opinion and getting product to ratify a territory-representation policy are the two long-lead items, and both sit outside the engineering critical path in a way that reliably makes them the actual schedule risk.

Recommendation. Adopt as a one-time seed source with the dependency removed after import, contingent on ODbL clearance. Do not adopt as a maintained runtime dependency. If legal cannot clear ODbL within two weeks, default to the MIT path and stop spending cycles on this evaluation — the dataset is a commodity, and the differentiation it offers is not worth an open licensing question in a commercial product.

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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core