Deleting records is a fundamental aspect of database management in any web application. Laravel’s Eloquent ORM provides a clean, expressive, and intuitive interface for removing records from the database. Whether you are deleting a specific row, deleting multiple rows based on a condition, soft deleting items for recoverability, or performing bulk operations, Eloquent makes the process elegant and powerful.
In this complete guide, we will explore the various methods of deleting records using Eloquent, how soft deletes work, the difference between destroy(), delete(), and forceDelete(), deleting through relationships, deleting multiple models at once, cascading deletes, model events related to deletion, best practices, and common pitfalls. This comprehensive article aims to help beginners and intermediate Laravel developers understand the full depth of deleting data with Eloquent.
Understanding Deletion in Eloquent
In Laravel, deletion is handled by the Eloquent ORM, which interacts directly with your database tables through model classes. When you delete a record using Eloquent, the ORM translates your method call into an SQL DELETE statement behind the scenes. Eloquent also provides mechanisms such as soft deletes, events triggered before and after deletion, and the option to force delete records permanently.
Deleting records should be done carefully because it affects the integrity of your database. Laravel includes several safety features to prevent accidental data loss, including mass assignment protection, guarded attributes, soft deleting, relationship constraints, and model events.
Basic Deletion Using the destroy() Method
The simplest way to delete a record using Eloquent is by calling the destroy() method. This method deletes records by their primary key.
Product::destroy(1);
In this example, the record with an ID of 1 will be removed from the database.
You can delete multiple records at once:
Product::destroy([1, 2, 3]);
Or:
Product::destroy(1, 2, 3);
The destroy() method is efficient and clean, making it the preferred choice when you already know the primary key of the record or records you want to delete.
Deleting Using the delete() Method
Another common method of deletion is to retrieve a model instance and then call delete() on it.
$product = Product::find(1);
$product->delete();
This approach is useful when you need to perform actions before or after deletion, such as running validation, checking conditions, or triggering model events.
Conditional Deletion With Query Builder Syntax
Laravel allows you to delete records based on conditions using the query builder style syntax:
Product::where('price', '<', 10)->delete();
This will delete all records where the price is less than 10.
Unlike destroy(), which deletes by primary keys, conditional deletion offers flexibility and is used for bulk deletion operations.
Difference Between destroy() and delete()
Understanding the difference between destroy() and delete() is important.
destroy()
Accepts primary key(s) directly and performs deletion without needing to load model instances.delete()
Must be called on a retrieved model instance or a query builder. It deletes all matching records.
Examples:
Using destroy:
Product::destroy(5);
Using delete:
Product::where('category_id', 3)->delete();
destroy() does not load models before deleting unless soft deletes are enabled. delete() typically loads models unless performed on a query.
Deleting a Retrieved Model
To delete a specific record after loading it:
$product = Product::where('name', 'Keyboard')->first();
$product->delete();
This is especially useful if you want to perform checks before deletion or if your model has relationships that depend on events.
Bulk Deletion Using delete()
You can delete multiple rows by using conditions:
Product::where('stock', 0)->delete();
Or using multiple conditions:
Product::where('is_active', 0)
->where('category_id', 4)
->delete();
Bulk deletion reduces the number of queries required and is efficient for large datasets.
How Soft Deletes Work in Eloquent
Soft deletes allow you to mark records as deleted without permanently removing them. This is useful for restoring data later or keeping logs for auditing.
To enable soft deletes in a model:
use Illuminate\Database\Eloquent\SoftDeletes;
class Product extends Model
{
use SoftDeletes;
}
Migration must include:
$table->softDeletes();
Once enabled, calling delete() does not remove the record. Instead, it sets the deleted_at timestamp.
Using Soft Deletes in Practice
Delete a record:
$product->delete();
Record remains in the database but marked as deleted.
Querying soft deleted records:
Product::withTrashed()->get();
Querying only deleted records:
Product::onlyTrashed()->get();
Restoring a soft deleted record:
$product->restore();
Restoring all records:
Product::onlyTrashed()->restore();
Permanently deleting a soft deleted record:
$product->forceDelete();
forceDelete() for Permanent Removal
forceDelete() bypasses soft deletes and removes the record permanently:
$product->forceDelete();
Use this method carefully, as it cannot be undone.
Deleting Related Models Through Relationships
You can delete related models using relationship methods.
Example of one to many:
$product->reviews()->delete();
This deletes all reviews related to the product.
Cascading Deletes
You can set delete behavior when defining relationships in migrations.
For example:
$table->foreignId('product_id')->constrained()->onDelete('cascade');
This means that deleting a product will automatically delete all related records.
Deleting Through belongsTo and hasMany
Deleting a parent model:
$product->delete();
You can trigger cascading deletes through events or database constraints.
Deleting child models:
$product->reviews()->delete();
Model Events for Deletion
Laravel fires events when a model is deleted:
- deleting
- deleted
- restoring
- restored
- forceDeleting
- forceDeleted
Example:
protected static function boot()
{
parent::boot();
static::deleting(function ($product) {
// Logic before delete
});
}
Events make it easy to perform additional actions.
Deleting Records Safely
Safety considerations for deletion:
- Only allow deletion through authorized actions using policies
- Validate conditions before deletion
- Implement soft deletes for recoverability
- Use database constraints for relational safety
- Log deletion actions
Implementing soft deletes is one of the best safety measures.
Conditional Deletion With Additional Logic
Example:
Product::where('status', 'expired')
->where('updated_at', '<', now()->subYear())
->delete();
This is useful for removing old or unused records.
Preventing Accidental Deletion
Using guarded attributes:
protected $guarded = ['id'];
Using model policies:
public function delete(User $user, Product $product)
{
return $user->isAdmin();
}
Deleting Records Only if They Exist
if ($product = Product::find($id)) {
$product->delete();
}
Deleting With Query Limits
Laravel does not provide limit() with delete, but you can use raw queries:
DB::table('products')->limit(10)->delete();
Deleting Records With Relationships Loaded
$product = Product::with('images')->find(1);
$product->images()->delete();
$product->delete();
This ensures related data is removed first.
Deleting All Based on Relationship Status
Product::has('reviews', '=', 0)->delete();
Deletes products with no reviews.
Deleting Pivot Table Records in Many to Many
$product->categories()->detach();
Or detach specific:
$product->categories()->detach([1, 2]);
Deleting Using Transactions
DB::transaction(function () use ($product) {
$product->images()->delete();
$product->delete();
});
Ensures atomic deletion.
Handling Large Scale Deletions
For very large tables:
- Use chunking
- Use queue jobs
- Use database level batch deletes
Example:
Product::chunk(100, function ($products) {
foreach ($products as $product) {
$product->delete();
}
});
Deleting Using Soft Delete and Restoring Later
Delete:
$product->delete();
Restore:
$product->restore();
Restore multiple:
Product::onlyTrashed()->restore();
Permanent Deletion After Soft Delete
Product::onlyTrashed()->forceDelete();
Best Practices for Deleting Records in Laravel
- Use soft deletes when possible
- Validate user permissions before delete
- Use model events for cleanup
- Handle cascading deletion correctly
- Avoid deleting large batches in a single query without chunking
- Always consider database integrity
- Use transactions when deleting dependent data
- Log deletion actions for auditing
Example Workflow of Deleting a Product
$product = Product::findOrFail($id);
$product->reviews()->delete();
$product->delete();
This ensures both parent and children are handled correctly.
Example of a Complete Soft Deletion Setup
In model:
use SoftDeletes;
protected $dates = ['deleted_at'];
In migration:
$table->softDeletes();
Delete:
$product->delete();
Restore:
$product->restore();
Force delete:
$product->forceDelete();
Leave a Reply