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

Eager Load Pivot Relations Laravel Package

audunru/eager-load-pivot-relations

Eager load relations on pivot models in Laravel Eloquent BelongsToMany relationships. Add the EagerLoadPivotTrait to the related model to load nested pivot data such as units or quantities. Supports Laravel 8 and above.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Data-modeling decisions: "rich pivot" vs. first-class entity. Many product domains naturally accumulate attributes on a join table — an annual procurement plan line carries qty, price, and unit_id; an order line carries a discount code; a team membership carries a role. This package makes the cheap modeling option (keep the pivot, add FKs and relations to it) viable in production, because you can still hydrate those relations without an N+1 storm. That lets you defer a costly schema refactor to a first-class LineItem model until the domain actually demands it.
  • List/report performance as a feature gate. Any roadmap item that renders a table or export of many parent records with per-row pivot lookups ("Plans → Items → Unit of measure", "Orders → Products → Supplier", "Subscriptions → Add-ons → Price book") is the trigger. The PM decision this informs is whether a feature ships on schedule or slips for a query-layer rewrite: Plan::with('items.pivot.unit') collapses what would otherwise be one query per row.
  • Build vs. buy for a ~1-class concern. The entire public surface is a single trait (EagerLoadPivotTrait) that overrides newBelongsToMany(). There is no service provider, facade, config, migration, or schema change. Buying costs one Composer line; building costs a day plus ongoing ownership of Eloquent internals knowledge. Adopting is the obviously cheaper option if the domain fits.
  • Scope/reuse: which models get the trait. This is a deliberately localized decision — add the trait only to models whose belongsToMany relations need pivot-relation hydration. It does not become a codebase-wide idiom, doesn't constrain the rest of the team's Eloquent usage, and is reversible per-model.
  • API contract for the front end / exports. Eager-load strings like items.pivot.unit.someRelation and nested pivot chains (...pivot.unit.someBelongsToManyRelation.pivot.otherRelation) become a shared contract between backend and API consumers. If you document these shapes, they become part of your public API surface — worth a deliberate naming decision (->as('planItem') vs. the default pivot) so payload keys read well to consumers.
  • Versioning/upgrade planning. Releases track Laravel majors explicitly (8/9/10 → 11 → 12 → 13), with PHP floors that step up (PHP 8.1 at Laravel 10, PHP 8.3 required at Laravel 13). This is a decision input for the platform-upgrade calendar: adopting adds a dependency whose major version must move in lockstep with your framework upgrade.

When to Consider This Package

Adopt when all of the following hold:

  • A belongsToMany relation is backed by a custom pivot model (->using(...)) that itself declares Eloquent relations — typically a foreign key to a lookup/reference entity (unit, currency, role, price tier, supplier).
  • You render or export collections of the parent model, so per-row pivot relation access would produce N+1 queries at a scale that matters (roughly: more than a handful of rows, or an endpoint with a latency budget).
  • You are on Laravel 8–13 and can accept the package's PHP floor for your target version.
  • You need the pivot data without immediately promoting the pivot to a standalone aggregate — i.e., the join table has attributes and relations but no independent lifecycle, routes, permissions, or audit requirements.
  • You want the change to be non-invasive: one trait, applied selectively, no migrations, no config, nothing published.

Look elsewhere — or don't adopt — when:

  • The pivot only holds scalars. If you just need qty and price, Laravel's built-in ->withPivot(...) already solves it and this package adds nothing.
  • The pivot is really an entity. If the join table needs its own CRUD screens, status workflow, soft deletes, or audit trail, promote it to a first-class model with hasMany/belongsTo and use ->through() or explicit queries. That's the right long-term shape, and the package would just be postponing it.
  • The query volume is trivial. A detail page loading 3 rows with one extra query each is not a problem worth a dependency.
  • Your organization restricts micro-dependencies. Honest signals here: 9 stars, 0 dependents, and it is a fork of a fork (ajcastro/eager-load-pivot-relations, itself by the same original author) maintained by a single person, with no downstream ecosystem to catch regressions. Some teams will reasonably prefer to vendor the class into app/ under their own test coverage.
  • You need guarantees. No SLA, no security policy beyond a recently added Trivy scan workflow, no vendor support. If the feature is business-critical, own the code.

If you do adopt with the risk above in mind, the mitigation is cheap: the package is small enough to read in full, so pin the version, add one integration test asserting the eager-load shape and query count, and treat "vendor it into the app namespace" as a live fallback rather than an emergency.

How to Pitch It (Stakeholders)

For executives (one paragraph): We have a small number of screens and exports where each row needs a detail from a lookup table — for example, each line of a plan or order needs its unit of measure or supplier. Today those produce one database query per row, which is invisible at demo volume but degrades linearly as customers add data. This package is a one-line addition that lets us load those details in a single batch instead of one-by-one, protecting response times as data grows. It requires no database changes, no migration, no infrastructure work, and no downtime; it touches only the handful of models that need it, and it can be removed as cleanly as it was added. Cost is effectively zero engineering days; the risk is a very small, single-maintainer open-source dependency, which we contain by pinning the version and covering the behavior with our own test.

For engineering (the short version): Add EagerLoadPivotTrait to the model that declares a belongsToMany relation; it overrides newBelongsToMany() to return a subclass that understands a pivot (or custom ->as() accessor) segment in eager-load strings. Plan::with('items.pivot.unit') then hydrates pivot relations in batch. Pivot classes stay plain Pivot subclasses — no changes needed to them. No service provider, no config, no migrations. Caveats to plan around: the trait must be on the model that defines the relation (for custom accessors, on the parent side too); required pivot FKs must be listed in ->withPivot(); and the package's major versions track Laravel majors with a rising PHP floor (PHP 8.3 for Laravel 13), so it joins your framework-upgrade checklist. It is a single-maintainer fork-of-a-fork with negligible adoption, so: pin it, add one test that asserts the load shape and the query count, and keep "copy the trait into app/" as a known, low-effort exit.

Recommendation: a timeboxed spike — instrument one real list endpoint, measure query count before and after — then adopt per-model where the numbers justify it. This is a tool for buying time on a data-model decision, not a substitute for making it.

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.
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode