alariva/modelmerge
Laravel package for merging duplicate Eloquent models. Move attributes and relationships from a source model into a target, then delete the obsolete record. Configurable merge behavior, events, transactions, and support for custom models.
Architecture fit. alariva/modelmerge targets the domain layer of a Laravel application, not infrastructure. It is a Composer-installed package that extends Eloquent's behaviour, most likely via a trait applied to models plus a service provider (auto-discovered) and a strategy object that defines "survivor" vs. "loser" records. This is a natural fit for a class of problems that almost every long-lived Laravel app eventually hits: duplicate entities created through multiple intake channels (SSO + manual signup, imported CRM contacts, re-created customers after a data migration, duplicate taxonomy terms). The scope is narrow and appropriate: merging two rows and reparenting related records is a well-bounded concern that should not be reimplemented per project.
Integration feasibility. Technically trivial to install (composer require alariva/modelmerge), the real question is version compatibility. With 17 stars, 0 dependents, and a composite score of 1.035, the package almost certainly predates current Laravel releases. The first gate is the composer.json constraint on illuminate/* and php — if it caps at Laravel 5.x/6.x and the target stack is 10/11, integration is blocked without a fork. Second gate is API surface: we need to confirm the merge strategy is declarative (map attributes, choose source of truth per field, whitelist relations) rather than a hardcoded "copy all non-null attributes and delete the source," which would be insufficient for anything with conflicts.
Technical risk. Merging is an inherently destructive, multi-table write. The risk profile is dominated by edge cases that a low-adoption package is unlikely to have hardened:
hasMany, belongsToMany (pivot rows), morphMany, and self-referential relations; missed relations leave orphans or violate FK constraints.customer_email rows) that abort mid-merge if the operation is not transactional.deleting, deleted, updated, and model events fire on the loser record, which downstream listeners (search indexing, webhooks, audit logs) depend on.Key questions. What are the exact Laravel/PHP version constraints and when was the last release? Which relation types are supported, and is reparenting configurable or automatic? Is the merge wrapped in a DB transaction and does it roll back on any failure? Is there a dry-run or preview capability? Does it support conflict resolution policies per attribute? Are model events dispatched for both survivor and loser? Does it handle polymorphic and pivot relations, and does it clean up pivots or leave them? What is the test suite coverage and is there CI? Is the maintainer active, and what is the license/contribution posture if we need to patch it?
Stack fit. Best fit is a Laravel monolith or modular monolith where Eloquent is the system of record and duplicates accumulate through organic growth or acquisitions. It is not appropriate for event-sourced or CQRS architectures where "merging" should be modelled as a domain event stream rather than a row rewrite. Strong candidate domains: CRM/contact management, customer accounts post-SSO consolidation, e-commerce customer dedup after store migrations, and taxonomy/tag consolidation.
Migration path. The Composer install is the easy part; the real migration is process, not code:
MergeService that owns the transaction boundary, authorization checks, dry-run, and audit logging. Treat the package as an implementation detail behind that seam so it can be replaced.Compatibility. Two dimensions: framework version (Composer constraints) and database behaviour (FK constraint enforcement, ON DELETE cascades, unique index strategy). If the app uses MySQL with strict FKs, missed relations will surface as hard failures — which is actually useful for testing, unlike SQLite. Confirm behaviour under both. Also check that the package respects the app's configured DB connection, since merges touching read replicas would be a correctness bug.
Sequencing. (a) Spike: run a merge against an anonymized production snapshot and diff the resulting rows and relation counts. (b) Build the wrapper with dry-run, transaction, and audit trail. (c) Build duplicate detection — the package does not solve identifying duplicates, and this is usually the larger effort. (d) Ship an admin/back-office UI or artisan command gated behind permissions. (e) Only then consider bulk/backfill dedup jobs, chunked and queued.
Maintenance. The dominant operational cost is ownership, not usage. A 17-star, single-maintainer package handling destructive writes means we should assume we may need to fork or vendor it. Pin to an exact version, mirror it in a private VCS or path repository, and budget a small but real ongoing allocation for upstream tracking. The codebase is likely small enough to audit fully before adoption — do that rather than trusting the README.
Support. Community-only, no SLA, low visibility into issue triage. For a package on the write path of customer records, that is a material risk. Mitigation: an internal fork we control, plus a documented decision record explaining why we did not build this in-house (the honest answer is that the merge logic is compact enough that in-house is a credible alternative if compatibility is poor).
Scaling. Merge operations are inherently low-volume — admin-initiated, one pair at a time — so throughput is not the concern. The concerns are (a) concurrency, where two operators merge the same record simultaneously and produce inconsistent state, requiring row-level locking or a queue-serialized merge command; and (b) bulk backfills, which must be chunked, idempotent, and rate-limited because each merge is a multi-table write and will hold locks. Long transactions on large relation sets can cause lock contention on hot tables.
Failure modes. Partial merges if the operation is not transactional; FK violations from unreparented relations; unique-key collisions mid-merge; orphaned pivot or polymorphic rows; lost attribute data because the loser's values were discarded without a policy; stale search indexes and caches; downstream webhooks and audit logs never firing because the loser was hard-deleted without events; soft-deleted records unexpectedly reappearing or being purged; and silent success where a relation type was simply not handled.
Ramp-up. Low to use — a Laravel developer can read the source and understand the API in an afternoon. Moderate to operate safely — the effort is in the surrounding scaffolding: duplicate detection, dry-run and diffing, authorization, audit trail, reversal/restore procedure, and stakeholder sign-off on the merge policy per entity. Plan for the merge policy definition to be a product/legal conversation as much as an engineering one, particularly where soft-deletes and PII retention are involved.
How can I help you explore Laravel packages today?