Laravel Context in Seeders: Clean Data Sharing Between Database Seeders

Laravel Context in Seeders: Clean Data Sharing Between Database Seeders

Database seeders often need to share created records, but traditional approaches lead to messy code and tight coupling. Laravel's Context provides a clean solution for seeder data flow.

When building complex database seeders, you frequently encounter scenarios where later seeders need access to records created by earlier ones. Traditional solutions involve static properties, global variables, or re-querying the database—all of which create maintenance headaches and unclear dependencies between your seeders.

Laravel's Context system transforms this challenge by providing a clean, type-safe way to share data across seeders. Instead of polluting your seeder classes with static properties or forcing unnecessary database queries, Context acts as a lightweight data bus that maintains clear separation of concerns while enabling seamless data flow.

Real-World Example

Consider an e-commerce application where you need to seed users, then create channels, and finally establish relationships between them. Here's how Context eliminates the complexity:

use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Context;

class UserSeeder extends Seeder
{
    public function run(): void
    {
        $user = User::factory()->create([
            'email' => 'admin@example.com',
            'role' => 'admin'
        ]);

        Context::add('user', $user);
        Context::add('admin_email', $user->email);
    }
}

use App\Models\Channel;
use App\Models\User;
use Illuminate\Container\Attributes\Context;
use Illuminate\Database\Seeder;

class ChannelSeeder extends Seeder
{
    public function run(
        // Retrieve context data with type-hinting
        #[Context('user')] User $user,
    ): void {
        $channel = Channel::factory()->create([
            'name' => 'General Discussion',
            'created_by' => $user->id
        ]);

        $channel->users()->attach($user, ['role' => 'moderator']);
        
        Context::add('main_channel', $channel);
    }
}

This approach eliminates several common anti-patterns: no more User::where('email', 'admin@example.com')->first() queries in dependent seeders, no static properties cluttering your seeder classes, and no tight coupling between seeders that makes testing difficult.

The Context system also provides type safety through the #[Context] attribute, ensuring your IDE can provide proper autocompletion and your code remains maintainable as your seeding logic grows more complex. This creates a clean dependency injection pattern that makes seeder relationships explicit and testable.

Stay Updated with More Laravel Tips

Enjoyed this article? There's plenty more where that came from! Subscribe to our channels to stay updated with the latest Laravel tips, tricks, and best practices:

Subscribe to Harris Raftopoulos

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe