Skip to content
Back to blog
LaravelPHPBuenas prácticas

Laravel 13.30.1 returns newly created rows without duplicate inserts

`insertOrIgnoreReturning()` makes idempotent imports simpler and removes extra queries just to find out what was inserted.

Ismael Catala3 min read

Inserting is easy, knowing what was inserted is harder

Importers, sync jobs, and queue workers often receive the same input more than once. A unique constraint can prevent duplicate records, but it is still common to insert first and run another query just to identify the rows that were actually added. That extra lookup adds state and makes a retryable workflow harder than it needs to be.

Laravel 13.30.1 includes an update around insertOrIgnoreReturning(). The Query Builder method accepts the values to insert, the columns to return, and an optional uniqueBy conflict target. Instead of only reporting an affected-row count, it gives back a collection containing the rows returned by the insert operation. (api.laravel.com)

A better fit for repeatable imports

This is useful when incoming data has a stable identifier, such as a vendor ID, a remote UUID, or a document key. A retry should not create another copy of something the database already knows about. At the same time, records that were newly inserted can immediately move into the next stage of the pipeline.

The following example stores items from an external API and asks for the local ID together with the external key. The external_id column needs a real unique constraint in the database, otherwise there is no reliable conflict to handle. The returned collection contains the items created during this particular operation.

use Illuminate\Support\Facades\DB;
 
$created = DB::table('external_items')->insertOrIgnoreReturning(
    [
        ['external_id' => 'api-1001', 'name' => 'Router'],
        ['external_id' => 'api-1002', 'name' => 'Switch'],
    ],
    ['id', 'external_id'],
    ['external_id'],
);
 
foreach ($created as $item) {
    SyncExternalItemMetadata::dispatch($item->id);
}

It now keeps the result through Eloquent too

The release also fixes the result handling when the method is called through an Eloquent builder. That matters in codebases that start from a model rather than from DB::table(). The point is not to turn the response into fully hydrated model instances, but to preserve the collection produced by the database query. (github.com)

I would use it when the insert result controls downstream work. For example, while importing documents for embedding generation, I would queue only the documents that were really created. It also suits scheduled synchronizations where replaying a batch must be safe without filling the code with pre-insert existence checks.

The fine print

This does not return rows that were already present in the table; it returns rows produced by the insert operation. If the next step needs both newly created and pre-existing records, the workflow needs another query or a different approach. Mixing up those two cases can leave data unprocessed during a synchronization.

It is not a replacement for database constraints either. uniqueBy describes which conflicts should be ignored, but the actual protection against duplicates comes from the appropriate unique key in the schema. Before using it in a critical importer, I would check the generated SQL and test the behavior against the database engine used by the application.

Finally, this should not become a reason to ignore every write error. An expected unique-key conflict is different from a dead connection, invalid data, or an unfinished migration. Idempotency belongs in the data model and should be tested with real job retries.

What I am leaving out for now

The release notes also mention changes related to schema operations and queue workers. However, the available official API reference does not yet expose those methods or the new event data with verifiable signatures. I would rather avoid publishing examples for an interface that cannot be checked against the official documentation.


Source: Laravel Framework v13.30.1 Official documentation: Illuminate Database Query Builder