Speeding Up Laravel Tests with tmpfs (MySQL in RAM)
If your Laravel test suite is painfully slow and does a lot of database work (multi-tenancy, migrations, seeding), the bottleneck is almost…
Ever messed up a production database with a failed migration? Yeah, me too. Let's fix that.
Laravel's Schema Builder already wraps schema changes in transactions. This means simple stuff like creating tables or adding columns is already safe:
Schema::table('users', function (Blueprint $table) {
$table->string('new_column');
});
But real migrations often do more than just schema changes. Maybe you're:
That's when you need to handle transactions yourself.
Here's the pattern you want to use:
public function up()
{
// 1. Schema changes - let Laravel handle transactions
Schema::table('products', function (Blueprint $table) {
$table->text('name')->change();
});
// 2. Data updates - wrap in your own transaction
DB::beginTransaction();
try {
DB::table('products')->update([
'name' => DB::raw("JSON_OBJECT('en', name)")
]);
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
throw $e;
}
// 3. More schema changes - Laravel's got this
Schema::table('products', function (Blueprint $table) {
$table->json('name')->change();
});
}
Don't try to wrap Schema changes in your own transactions:
// This will blow up with "There is no active transaction"
DB::beginTransaction();
Schema::table('products', function (Blueprint $table) {
$table->string('name');
});
That's it. Now your migrations won't leave your database in a weird state when they fail.
For huge data updates, consider chunking:
DB::beginTransaction();
try {
DB::table('huge_table')->orderBy('id')->chunk(1000, function ($records) {
foreach ($records as $record) {
// Do your updates
}
});
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
throw $e;
}
Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.
Take a look at vroni.com