Laravel RefreshDatabase vs DatabaseTransactions is one of the most common sources of confusion when writing tests in Laravel.
Choosing the wrong approach can lead to flaky tests, hidden bugs, and unreliable results.
When writing tests in Laravel, database state can quickly become a source of confusion.
One test passes, another fails. Data seems to “leak” between tests. Records appear when they shouldn’t — or disappear when you expect them to exist.
If you’ve experienced this, you’re not alone.
In most cases, the issue comes down to how your tests handle the database. Laravel provides two primary approaches for this:
- RefreshDatabase
- DatabaseTransactions
At first glance, they seem similar. In reality, they behave very differently — and choosing the wrong one can lead to subtle bugs or false confidence in your test suite.
Understanding the Core Problem
Tests must be isolated.
Each test should run independently, without being affected by previous tests.
If your database is not reset properly between tests:
- data can persist unexpectedly
- test results become unreliable
- debugging becomes painful
Laravel solves this problem using two strategies:
- Reset the database completely
- Wrap each test in a transaction and roll it back
Option 1: RefreshDatabase
use Illuminate\Foundation\Testing\RefreshDatabase;
class UserTest extends TestCase
{
use RefreshDatabase;
}
How it works
- Runs migrations before tests
- Ensures a clean database state
- Uses transactions internally when possible
Advantages
- High reliability
- Works with queues, jobs, events
- Predictable behavior
Disadvantages
- Slower
- Heavier setup
Option 2: DatabaseTransactions
use Illuminate\Foundation\Testing\DatabaseTransactions;
class UserTest extends TestCase
{
use DatabaseTransactions;
}
How it works
- Starts a database transaction before each test
- Rolls it back after the test finishes
Advantages
- Fast
- Lightweight
Disadvantages
Does NOT work well with queues or async processes
Can lead to hidden inconsistencies
When to Use Each
Use RefreshDatabase when:
- testing queues or jobs
- working with multiple DB connections
- you need maximum reliability
Use DatabaseTransactions when:
- testing simple DB logic
- performance is critical
- everything runs in one request lifecycle
Where Things Break in Real Projects
This is where most developers run into problems.
Especially when:
- jobs don’t see database data
- tests pass locally but fail in CI
- retries cause unexpected behavior
-> I go deeper into real-world failures, debugging strategies, and edge cases here:
-> https://codecraftdiary.com/2026/03/28/laravel-refreshdatabase-vs-databasetransactions/
TL;DR
Use RefreshDatabase for reliability
Use DatabaseTransactions for speed
Avoid mixing both
Be careful with queues and async behavior
If you're working with Laravel testing, you might also find useful:
Queue testing pitfalls
-> https://codecraftdiary.com/2026/03/08/laravel-queue-testing-jobs-retries/
Feature testing in PHP
-> https://codecraftdiary.com/2025/10/30/feature-testing-in-php-ensuring-the-whole-system-works-together/
Top comments (0)