hardevine/shoppingcart
hardevine/shoppingcart is a Laravel shopping cart package (a maintained fork of LaravelShoppingcart) offering simple cart management: add, update and remove items, track quantities and prices, apply conditions, and persist carts via sessions for newer Laravel versions.
hardevine/shoppingcart is a community-maintained fork of the long-standing Crinsane/LaravelShoppingcart package. It is a session-backed cart primitive: a Cart facade over a session-stored collection of line items, with a small API (add, update, remove, content, total, subtotal, tax, destroy, store/restore), item-level and cart-level "conditions" for discounts/vouchers, and one level of nested child items. It is deliberately narrow: no persistence layer, no product/stock/price models, no currency model, no checkout, no order state machine. It is a calculator with a session store, not a commerce engine.
Change since last assessment (v3.4): the release note is a single line — "Supports L12." No new features, no API changes, no deprecations announced. This is a compatibility-only release and does not alter the package's shape or our integration design. It does partially close one open question (framework support) and is a mild positive signal on maintainer cadence, since it landed in step with the current Laravel major. Treat it as a maintenance signal, not a capability change.
Architecture fit
| Dimension | Assessment |
|---|---|
| Fit for a Laravel monolith with server-rendered checkout | Strong. Installs in minutes, no schema, no external services. |
| Fit for headless/API-first or SPA commerce | Weak. Session coupling makes it awkward behind Sanctum/token auth and multi-device cart merge. |
| Fit for multi-currency, B2B pricing, or tax-jurisdiction logic | Poor. Single tax rate in config; prices are caller-supplied floats. |
| Fit as a system of record | No. Cart state lives in the session and is lost or orphaned by nature. |
| Fit as a pricing/line-item domain component | Reasonable, if wrapped behind your own interface so pricing rules stay in your code, not in the package. |
Integration feasibility — High, and marginally improved by 3.4: on a Laravel 12 codebase we can now consume the package on its current release line rather than pinning to an older frame. Composer install, package auto-discovery, one published config file (config/shoppingcart.php: tax rate, number/number format, conditions). No migrations, no queues, no credentials. A working cart is achievable in a single spike session.
Technical risk
| Risk | Severity | Notes |
|---|---|---|
| Money stored as floats | High | Totals are float arithmetic; rounding policy is yours to impose. Rounding drift at scale is a real reconciliation problem. Unchanged by 3.4. |
| Session as datastore | High | Cart dies with session expiry, cookie clearing, or deploy that changes session driver. Cross-device carts require custom store()/restore() work. Unchanged by 3.4. |
| Price staleness | High | Line-item prices are snapshotted at add-to-cart; catalogue changes, promotions, and tax changes silently diverge from what the user sees vs. what you charge. You must revalidate at checkout. Unchanged by 3.4. |
| No concurrency control | Medium | Last-write-wins across tabs; no locking on quantity mutation. |
| Fork lineage | Medium | Inherits upstream design and quirks; behaviour/upgrade path depends on one maintainer's cadence. Slightly reduced: 3.4 delivering L12 support on the current major is evidence of an active, framework-tracking release habit rather than abandonware. Still a single-maintainer bus factor. |
| Ecosystem immaturity | Medium | 356 stars and effectively no downstream dependents means few battle-tested production paths and thin third-party guidance. Unchanged. |
| Test/quality signal | Medium | Verify coverage and CI matrix before committing; a score of ~7.3 with a high "opportunity" signal suggests a package with real utility but known rough edges. The 3.4 CI matrix is the concrete artefact to inspect. |
| Security surface | Low | MIT, small surface, no auth/network code. Main exposure is trust in session integrity and unescaped display of cart contents by your own views. A framework-support bump is a low-risk change class. |
Key questions
Crinsane/LaravelShoppingcart — is it a drop-in replacement, and will fixes be upstreamed or stay local?Stack fit — Best suited to a conventional Laravel monolith using the default session driver, Blade/Livewire checkout, and a server-side catalogue. If our target is a decoupled SPA or mobile client, I would not adopt this package as-is; the session coupling would force a custom persistence/identification layer that erodes the time saved. With 3.4, a Laravel 12 monolith is now a first-class target rather than a stretch.
Migration path
Cart:: calls leak into controllers and views. Define an application-level CartService/CartRepository interface with our own DTOs (line item, totals, applied adjustments) and implement it using hardevine/shoppingcart. This is the single most important decision — it makes the package replaceable if pricing or multi-currency requirements outgrow it. A compatibility-only release like 3.4 is exactly the scenario this boundary is designed to absorb.store()/restore() for login merge and cross-device continuity. This gives us abandonment analytics and recovery without forking the package.composer update.Compatibility — Three compatibility axes now matter: (a) the framework/PHP matrix — 3.4 confirms Laravel 12, PHP matrix unconfirmed; (b) whether the L12 support bump is a hard constraint change (composer require floor moved) that ripples into our dependency set; and (c) compatibility of the fork with the ecosystem's existing documentation and Stack Overflow answers, which overwhelmingly describe upstream Crinsane behaviour. Expect namespace differences (Hardevine\Shoppingcart\Facades\Cart) and some API drift versus older tutorials; budget time for that during onboarding. Pin to ^3.4 on a Laravel 12 codebase; if we are still on Laravel 11, confirm the previous minor remains installable before sequencing the framework upgrade.
Sequencing (typical 3–5 sprint engagement, cart-only scope)
| Phase | Work | Exit criteria |
|---|---|---|
| 0. Spike (2–3 days) | Sandbox install on the target framework version (L12 via 3.4), config publish, add/update/conditions/nested items, session-driver behaviour across requests | Documented gap list, especially rounding and tax behaviour; confirmed PHP matrix |
| 1. Boundary | CartService interface + adapter, DTOs, unit tests around totals |
Controllers/views depend only on our interface |
| 2. Identity & merge | Guest cart key, login merge, cross-device restore, expiry policy | Documented merge semantics; abandoned-cart events emitted |
| 3. Pricing hardening | Integer money, tax/discount ordering, checkout revalidation, rounding tests | Reconciliation test proves cart total == order total for a fixture matrix |
| 4. Hardening | Concurrency tests (multi-tab), session-loss UX, telemetry, upgrade runbook | Runbook + alerting in place before launch |
No resequencing is required by 3.4; it only removes the "will this work on our framework version" unknown from Phase 0.
Operational Impact
Maintenance — Low day-to-day cost and low upgrade cost: a handful of classes, no schema, no migrations, no background jobs, no infrastructure. The real maintenance is ours: the adapter, pricing layer, and merge logic. Two ongoing obligations: track package releases against our Laravel upgrade cadence, and keep our pricing logic separate so a fork going quiet is a contained, not existential, problem. 3.4 is a good data point for the first obligation — record it in the upgrade log and pin the new floor.
Support — MIT with no commercial backing and no SLA. Support is GitHub issues plus reading source. Given the high "opportunity" signal and minimal downstream dependents, we should assume we may need to vendor-patch. Budget a named owner (roughly 5–10% of one engineer) for upstream triage; treat the fork's bus factor as a tracked risk with a documented exit path (swap the adapter to an in-house implementation). The L12 release is reassuring on cadence but does not change the absence of a support commitment.
Scaling — No scaling cost from the package itself, and none added by 3.4. Session-backed carts still constrain horizontal scale: we need shared session storage (Redis or database sessions) and sticky-session-free routing. Session payload grows with cart size and nested items — keep carts small (cap line count, avoid unbounded child items) and monitor session size, since large serialized carts increase Redis/DB session I/O and cookie/response overhead. Analytics and abandonment reporting are not available from the session store and must come from our own cart-identity table.
Failure modes
| Failure | User-visible effect | Mitigation |
|---|---|---|
| Session expiry / driver change on deploy | Silent empty cart, lost conversion | Persist cart key server-side, restore on next request, "your cart was saved" messaging |
| Catalogue price or tax change after add | Displayed total ≠ charged total | Revalidate and re-price at checkout; show explicit change notice |
| Float accumulation across many lines/conditions | Off-by-a-cent totals, refund/reconciliation noise | Integer minor units, explicit rounding at defined points, fixture-based tests |
| Condition stacking (voucher + promotion) | Negative totals, double discount, order-dependent results | Deterministic ordering rules in our pricing layer; clamp at zero; regression suite |
| Multi-tab quantity edits | Last-write-wins, duplicate/incorrect quantities | Optimistic versioning in our adapter, or accept and validate at checkout |
| Item out of stock after add | Order fails at payment | Availability re-check in the checkout step, not the cart step |
| Abandoned/orphaned cart keys | Storage growth in our identity table | TTL and cleanup job |
| Minor-version upgrade breaks session cart shape | Existing users' carts deserialize wrong or empty after deploy | Pin versions, run the cart round-trip test in CI on upgrade, deploy behind a session-compatible window; low likelihood for a compatibility-only release like 3.4 |
Ramp-up — A mid-level Laravel engineer reaches productivity in roughly half a day: the API is small and the config is one file. The non-obvious parts — nested/child items, condition ordering, tax application semantics, and store()/restore() behaviour — need a short internal write-up and a handful of tests to become team knowledge. The steeper learning curve is not the package but the pricing/rounding discipline we impose around it; that belongs in onboarding docs, not in the developer's head. Nothing in 3.4 changes this.
Recommendation — Adopt for a conventional Laravel monolith cart, wrapped behind our own interface, with integer money and checkout revalidation owned by us. Version 3.4 (Laravel 12 support) removes the framework-support caveat on a current Laravel codebase and is a mild positive on maintainer cadence, but it is a compatibility release only and does not narrow the package's structural limits. Do not adopt as the system of record, and re-evaluate if multi-currency, headless clients, or complex promotion rules become requirements — at that point the adapter should be replaced rather than the package forked.
How can I help you explore Laravel packages today?