Laravel v12.54.0 adds Model::withoutRelation() for selectively unloading relations from a cloned model instance, introduces interval() on InteractsWithData for parsing duration inputs, and includes a composite index on the jobs table for improved queue polling performance.
Key highlights include:
Model::withoutRelation()to selectively unload loaded relations without mutating the originalinterval()method onInteractsWithDatafor converting request data toCarbonInterval- Request context (method, URL, status) included in HTTP client
Response::dump()output BinaryFileResponseassertion support in HTTP testsqueue:monitordisplays oldest pending job in standard output- Custom CommonMark extensions for mail Markdown rendering
- Composite index on the jobs table for queue polling performance
- PostgreSQL
tsvectorcolumn type in the schema builder
What's New
Model::withoutRelation()
Model::withoutRelation() creates a cloned model instance with specific relations removed, without mutating the original. This fills the gap between withoutRelations() — which removes all relations — and unsetRelation(), which mutates the model in place.
// Remove a single relation from a clone$lightweight = $post->withoutRelation('comments'); // Remove multiple relations$lightweight = $post->withoutRelation(['comments', 'tags']); // Original is untouched$post->relationLoaded('comments'); // true
This is useful for handling circular references, reducing payload size in queued jobs, and preparing models for serialization without stripping all eager-loaded data.
Pull Request: #59137
interval() on InteractsWithData
A new interval() method on InteractsWithData converts request input into a CarbonInterval instance. It accepts ISO 8601 duration strings directly, or numeric values paired with a unit.
// ISO 8601 duration string ("P1DT2H" → 1 day, 2 hours)$request->interval('duration'); // Numeric value with a string unit$request->interval('timeout', 'second'); // "90" → 90 seconds$request->interval('cooldown', 'day'); // "7" → 7 days // Or using the Carbon\Unit enum$request->interval('delay', Unit::Minute);
This joins date() as a time-related helper on request data, giving forms a native way to handle duration inputs.
Pull Request: #59114
Request Context in Response::dump()
Response::dump() on the HTTP client now includes the request method, URL, and response status code alongside the response body. Previously, dump output showed only the response body, making it difficult to identify which request produced a given response when chaining multiple calls.
// Before{"error": {"message": "Invalid card"}} // After"POST https://api.stripe.com/v1/charges" 422{"error": {"message": "Invalid card"}}
Pull Request: #59136
BinaryFileResponse Assertion Support
Test responses returned by response()->file() and response()->download() now support streamed content assertions. Previously, calling assertStreamedContent() on a BinaryFileResponse would fail because the test response couldn't read the underlying file.
$this->get('/download/report.pdf') ->assertOk() ->assertStreamedContent(file_get_contents('report.pdf'));
Pull Request: #59018
queue:monitor Displays Oldest Pending Job
The queue:monitor command now shows the oldest pending job age in its standard text output. Previously this detail was only available in JSON output, so you had to parse JSON or check the queue driver directly to spot stale jobs.
Pending jobs ...................................... 3Delayed jobs ...................................... 0Reserved jobs ..................................... 1Oldest pending job ................................ 2 minutes ago
Pull Request: #59073
Custom Markdown Extensions for Mail
Mail Markdown rendering now supports custom CommonMark extensions via the mail.markdown.extensions configuration key. Previously, only the Core and Table extensions were loaded.
// config/mail.php'markdown' => [ 'extensions' => [ League\CommonMark\Extension\Strikethrough\StrikethroughExtension::class, League\CommonMark\Extension\TaskList\TaskListExtension::class, ],],
Any extension implementing the CommonMark ExtensionInterface can be registered here.
Pull Request: #59051
Composite Index on Jobs Table
The jobs table migration now creates a composite index on (queue, reserved_at, available_at) instead of a single-column index on queue. On busy queues, the previous single-column index left the database scanning rows to filter by reserved_at and available_at on every poll. The new composite index aligns with the actual shape of the queue polling query, which filters on all three columns.
This is a new migration and only applies to fresh installs or applications that re-run their migrations. Existing applications should add the composite index manually if they need the improvement.
Pull Request: #59111
PostgreSQL tsvector Column Type
The schema builder now supports the tsvector column type for PostgreSQL, removing the need for raw SQL when defining full-text search columns.
Schema::table('articles', function (Blueprint $table) { $table->tsvector('search_vector')->nullable()->storedAs( "setweight(to_tsvector('english', coalesce(title, '')), 'A') || " . "setweight(to_tsvector('english', coalesce(body, '')), 'B')" );});
Pull Request: #59004
Bug Fixes and Improvements
Queue & Jobs:
- Prevent queue deadlock when job reservation throws an exception (e.g., attempts overflow) (#58978)
- Fix division by zero error in
repeatEvery()(#58987)
Database:
- Fix
migrate:freshfailing when the database does not exist (#59113) - Fix enum handling in
ModelNotFoundExceptionerror messages (#59132)
HTTP & Filesystem:
- Fix URL validation for punycode subdomains (#58982)
- Suppress chmod errors in
Filesystem::replace()on non-POSIX filesystems (#59126) - Fix facade cache file permissions (#59059)
Console & Views:
- Deduplicate paths in
view:cache(#59145) - Fix
TwoColumnDetailstripping trailing punctuation from second column values (#59010) - Allow
app.editor.base_pathto be an empty string (#58991)
Other:
- Fix Redis throttle ignoring
aftercallbacks (#58990) - Fix after-commit observers breaking
-ingevent cancellation (#59058) - Fix array offset deprecation warnings (#59019)
- Update CommonMark version constraint to address a
DisallowedRawHtmlRenderersecurity issue (#59131)