brick/money
Brick\Money is a PHP library offering immutable Money and Currency classes with exact arithmetic and explicit rounding control, avoiding floating-point errors. Built on brick/math, it handles any amount size. Requires PHP 8.2+; GMP or BCMath recommended for speed.
Architecture fit
brick/money is a domain library, not a Laravel package: there is no service provider, config file, facade, migration, or Eloquent trait. That is not a defect — it is a deliberate scope choice — but it means it slots into the model layer, not the framework layer. For a TPM the relevant question is not "does it integrate with Laravel" but "where in our domain do we want a single, replaceable money abstraction."
The fit is strongest where money is currently handled as float, decimal, or bare integers with implicit currency:
RationalMoney lets you defer rounding to a single, auditable point.allocate() with explicit allocation modes encodes a policy decision that is otherwise buried in ad-hoc code.MoneyBag and the FX conversion layer give you a currency-safe aggregate type.CashContext models CHF-style 5-cent increments that a generic decimal type cannot express.Fit is weaker where you need: persisted monetary columns with database-level arithmetic (SQL SUM, reporting joins), or a team with no tolerance for pre-1.0 semver. In those cases the library is still the right in-process representation, but you must own the storage and aggregation contract yourself.
Integration feasibility
High. composer require brick/money on PHP 8.2+, one transitive dependency (brick/math), MIT license, no extensions required but GMP/BCMath strongly recommended for performance. Nothing in the package reaches into framework internals, so Laravel 10/11/12 compatibility is essentially a PHP-version question, not a framework-version question.
The real integration work is ours and is modest but non-zero: an Eloquent cast (Money ⇄ BIGINT minor units + CHAR(3) currency), a validation rule for currency codes and scale, an API resource/formatter for display, and a config-driven default currency + default rounding policy. That is roughly 1–2 days of engineering for a first vertical slice.
Technical risk
0.x.y; breaking changes always start a new 0.x cycle. Pinning 0.14.* is safe, but the team must treat minor bumps as major bumps during review. This is the largest process risk, not a technical one.EUR, USD) are breaking; numeric codes, country lookups, and historical currencies may change in minor releases. Anything that persists a currency code across time needs a test that asserts the code resolves.RoundingMode at every lossy operation. If there is no written rounding policy per use case (tax, discount allocation, FX, refunds), developers will pick modes inconsistently and you will get reconciliation defects that are hard to attribute. This is the failure mode I would actually budget for.Dependents: 0 and a release date of 2026-09-29 — both are almost certainly scraping artifacts (this is a widely depended-on library, and that date is in the future). Verify current versioning and download counts on Packagist before quoting either number upward.Money through queues, caches, API payloads) need an explicit decision: persist minor units + code, never the object's string form.Key questions
RationalMoney (deferred rounding) or is per-operation Money with explicit modes sufficient?BIGINT minor units, or DECIMAL(19,4) plus scale metadata?0.10 for 8.1?Stack fit
Framework-agnostic and PHP-version-gated, which is the cleanest kind of fit: no Laravel version treadmill, no conflict with existing providers. Recommended shape is a thin application-owned boundary — a MoneyFactory/CurrencyRegistry service, an Eloquent cast, an Http resource formatter, and a validation rule — with the library confined to those adapters plus domain services. Do not let Brick\Money\* types leak into controllers or Blade templates; keep them in models and services so the representation stays swappable.
Migration path
Brownfield migration should be incremental and observable, not a big-bang refactor:
money config (default currency, default rounding mode, approved modes).amount_minor BIGINT, currency CHAR(3)) alongside existing float/decimal columns on one high-value table.Money::ofMinor() on read and asserting equality against the legacy column in a nightly check.For greenfield, start with minor-unit integers from day one; do not introduce decimal columns "for readability."
Compatibility
Requires PHP 8.2+ for current releases (0.10 for 8.1, 0.8 for 8.0). The library tracks the latest ISO 4217 standard, so compatibility includes data compatibility, not just code compatibility. brick/math must be allowed to float within the range the chosen brick/money cycle supports — pin both or pin neither, but pin consistently. GMP or BCMath should be present in the production image; without them the library still works but falls back to slower pure-PHP arithmetic.
Sequencing
Phase 1: config, cast, validation rule, formatter, and the rounding policy doc. Phase 2: one vertical slice (cart totals or invoice lines) with dual-write and reconciliation. Phase 3: RationalMoney for any multi-step calculation (tax-then-discount-then-FX) where intermediate rounding currently causes drift. Phase 4: allocation/split for payouts and refunds, with the chosen AllocationMode documented as a business rule. Phase 5: MoneyBag and FX providers only once genuine multi-currency reporting is on the roadmap.
Maintenance
Low code churn, moderate process churn. The library is stable and well tested, but the 0.x cadence means someone must own upgrade reviews, and currency-data updates arrive with releases rather than as separate data packages. Budget a recurring task: read the changelog on each 0.x.0, run the currency-code assertions, and confirm rounding behavior is unchanged. Because there are no framework hooks, there is nothing to keep in sync with Laravel releases — a genuine long-term win.
Support
Support burden shifts from "why is the library broken" to "why did this total change by a cent." Expect tickets about rounding, not about crashes. Mitigations: log the rounding mode used on any lossy operation, surface currency and minor units in admin views, and keep an audit trail of the pre-rounding rational value for high-value flows (invoices, payouts). The library's exception messages are specific and actionable, which shortens triage.
Scaling
Effectively free. Immutable value objects, pure in-process arithmetic, no I/O, no state, no caches. With GMP/BCMath the operations are fast enough that this will never appear in a profile. The one scaling consideration is at the data layer: aggregate reporting must sum integers or decimals in SQL, not hydrate thousands of Money objects — so the storage schema decision made during integration is what actually determines reporting performance.
Failure modes
RoundingNecessaryException at runtime wherever a mode was omitted — the most likely production incident, and it is a design signal rather than a bug. Enforce modes at the service boundary so this never reaches a user request.CurrencyMismatchException on cross-currency arithmetic — desirable, but needs a user-facing translation in API error handling.UnknownCurrencyException on ISO data changes or user-supplied codes — validate at input, and assert persisted codes resolve after every upgrade.AutoContext with an infinite repeating decimal throws rather than approximates; document that it is unsuitable for intermediate results and steer developers to RationalMoney.Ramp-up
A competent PHP developer is productive in half a day for basic of()/plus()/minus(). The genuine learning curve is conceptual: contexts (default vs. cash vs. custom vs. auto), the difference between Money and RationalMoney, and why rounding is never implicit. Plan a one-hour team session plus the written rounding policy — without that doc, the library's main safety feature (forced explicitness) becomes a source of inconsistent decisions rather than a control.
How can I help you explore Laravel packages today?