gerardojbaez/money
A Laravel package for working with monetary values through an expressive API. It simplifies formatting, parsing, and converting currencies, making it easy to display prices and handle money safely in PHP code and Blade templates.
composer require gerardojbaez/money
Laravel will auto-discover the service provider on supported versions. If you are on an older Laravel, register Gerardojbaez\Money\MoneyServiceProvider manually. Publish the config so you can edit currency symbols, decimal places, separators, and format order:
php artisan vendor:publish --provider="Gerardojbaez\Money\MoneyServiceProvider"
Look first at:
config/money.php — the 91-entry currency table; this is where symbol, format, decimal places, thousands separator, and decimal mark live.src/Money.php — the value object and format() implementation.src/Currency.php — how a currency code is resolved and what happens when it is not in the table.The simplest first use case is replacing number_format()/money_format() calls in a Blade view or API response:
use Gerardojbaez\Money\Money;
echo (new Money(1299.99, 'USD'))->format(); // $1,299.99
echo (new Money(49999, 'INR'))->format(); // ₹49,999.00 (symbol per config)
Amount plus ISO code in, formatted display string out. That is the core loop.
Format at the edge, store raw values. Keep amount (integer minor units or a decimal string) and currency (ISO 4217 code) in the database. Instantiate Money only in presenters, Blade components, API resources, or mail templates. Never persist the formatted output — the archived currency table will eventually be wrong for some currency and you will want to change formatting without a data migration.
Wrap it in one application-level formatter. Rather than sprinkling new Money(...) everywhere, centralize it:
final class MoneyFormatter
{
public function format($amount, string $currency, ?string $locale = null): string
{
return (new Money($amount, $currency))->format();
}
}
This gives you one place to swap in intl/NumberFormatter later, or to add per-tenant formatting overrides. It also keeps the package's API surface out of your domain code.
Use it in Blade via a component or directive. A small Blade component keeps templates readable and makes the escaping story explicit:
<x-money :amount="$order->total" :currency="$order->currency" />
Return both raw and formatted values from APIs. Consumers often need the machine-readable value for calculations and the display string for UI:
return [
'total' => $order->total,
'currency' => $order->currency,
'total_formatted' => (new Money($order->total, $order->currency))->format(),
];
Override currency metadata in config instead of subclassing. For a currency where the shipped config does not match your business rules — for example forcing zero decimals on a display-only currency, or changing the INR symbol from ₹ to Rs. — edit the relevant entry in config/money.php. This is the intended extension point and avoids forking Money for cosmetic changes.
Test against fixed expectations. Because the package is locale-independent by design, formatted output is deterministic. Assert exact strings in feature tests; this catches accidental config changes and makes upgrades safe:
$this->assertSame('$1,234.56', (new Money(1234.56, 'USD'))->format());
Delegate math to your own layer. Use the package only for rendering. Summing, tax calculation, rounding policy, and currency conversion should happen in domain code using integers or bcmath. Treat Money as a presenter, not an accounting primitive.
composer.json and consider vendoring or forking. Do not expect fixes for PHP 8.x deprecations, newer Laravel versions, or missing currencies. The package is small enough that a fork is realistic if you need changes.format() is deliberately simple. It does not implement the full money_format() spec — no locale-driven negative parentheses, no full %n semantics. If you need accounting-style negatives or locale-aware grouping, use NumberFormatter from ext-intl and keep this package only for the simple cases.1.005. Pass pre-rounded values, integer minor units divided at the boundary, or decimal strings. The formatter is not a rounding engine.src/Currency.php to see whether an unknown ISO code throws, silently falls back, or formats without a symbol. Guard currency codes at validation time so bad data does not reach the formatter.config/money.php, run php artisan config:clear locally and php artisan config:cache in deploy. A stale cached config is the most common reason a symbol change “does not apply.”-1234.56 renders in your configured format before shipping invoice templates; do not assume parentheses or a sign position.Money is not resolvable, check config/app.php providers/aliases before debugging the package itself.config/money.php allows — multi-currency rounding rules, per-locale grouping, symbol placement by context — replace the internals of your MoneyFormatter with intl while keeping the call sites stable.How can I help you explore Laravel packages today?