Configure Laravel's Date facade to use CarbonImmutable by default, and automate migrating legacy Carbon calls with Rector.
By default, Carbon instances in PHP are mutable. Modifying a date instance unexpectedly alters the original variable:
$date = now();
$tomorrow = $date->addDay();
// Both variables now point to tomorrow!
echo $date->toDateString(); // 2026-09-04
echo $tomorrow->toDateString(); // 2026-09-04
1. Configure the Date Facade
In AppServiceProvider::boot(), instruct Laravel's Date factory to generate CarbonImmutable instances:
namespace App\Providers;
use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
Date::use(CarbonImmutable::class);
}
}
Once configured, all calls through the Date facade as well as Laravel helpers (now(), today()) return immutable instances:
$date = now();
$tomorrow = $date->addDay();
echo $date->toDateString(); // 2026-09-03 (original remains unchanged)
echo $tomorrow->toDateString(); // 2026-09-04
2. The Direct Carbon Trap
While Date::use(CarbonImmutable::class) secures now(), today(), and Date::now(), any code directly calling Carbon::now() or Carbon::parse() bypasses Laravel's date factory and remains mutable:
use Carbon\Carbon;
// ❌ Bypasses Laravel's Date factory; remains mutable
$date = Carbon::parse('2026-09-03');
// ✅ Routes through Date factory; returns CarbonImmutable
$date = Date::parse('2026-09-03');
3. Automate Codebase Migration with Rector
To migrate an existing codebase so all static Carbon calls route through Laravel's Date facade, use `CarbonToDateFacadeRector` from rector-laravel:
composer require --dev driftingly/rector-laravel
Register the rule in rector.php:
// rector.php
use Rector\Config\RectorConfig;
use RectorLaravel\Rector\StaticCall\CarbonToDateFacadeRector;
return RectorConfig::configure()
->withRules([
CarbonToDateFacadeRector::class,
]);
What Rector Automatically Transforms
// Before Rector:
use Carbon\Carbon;
$now = Carbon::now();
$date = Carbon::parse('2026-01-01');
// After Rector:
use Illuminate\Support\Facades\Date;
$now = Date::now();
$date = Date::parse('2026-01-01');
Key Benefits
- Predictable Date Math: Operations like
addDay()orsubMonth()always return new instances without mutating source dates. - Framework Uniformity: Using
Date::use(CarbonImmutable::class)guarantees all Eloquent timestamps, cast dates, and helpers share the same immutable behavior. - Automated Modernization:
CarbonToDateFacadeRectorremoves manual search-and-replace across legacy controllers and services.