# How to Use Laravel Seeders to Populate Production Data: A Complete Guide

> Learn to use Laravel seeders to safely populate production data with factories raw inserts and dependency injection Control model events and output verbosity for a smoother workflow

- Repository: [Laravel/framework](https://github.com/laravel/framework)
- Tags: how-to-guide
- Published: 2026-02-16

---

**Laravel seeders provide a container-aware architecture through `Illuminate\Database\Seeder` that lets you safely populate production databases using factories, raw inserts, and dependency injection while controlling model events and output verbosity.**

Laravel's database seeding system, implemented in the `laravel/framework` repository, offers a robust solution for programmatically filling your database with realistic data. Whether you need to bootstrap essential lookup tables or import complex production datasets, understanding how to use Laravel seeders effectively ensures your data population strategy remains maintainable and safe across environments.

## Understanding the Laravel Seeder Architecture

### The Seeder Base Class

At the core of every seeder lies `Illuminate\Database\Seeder`, defined in [`src/Illuminate/Database/Seeder.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Seeder.php). This abstract base class provides the foundation for all database seeding operations through several key mechanisms:

- **`call()`** – Resolves other seeders through the IoC container and tracks which have run to prevent duplicates.
- **`__invoke()`** – Ensures a `run()` method exists and executes it, optionally inside a `withoutModelEvents` context.
- **`callSilent()`** – Executes seeders while suppressing console output, useful for production environments where noise should be minimized.
- **`withoutModelEvents()`** – Wraps operations in a closure that disables model observers, significantly improving performance during bulk inserts.

### The SeedCommand Console

The Artisan command `php artisan db:seed` is handled by `Illuminate\Database\Console\Seeds\SeedCommand`, located in [`src/Illuminate/Database/Console/Seeds/SeedCommand.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Console/Seeds/SeedCommand.php). This command performs several critical safety operations:

1. Boots the database connection specified via the `--database` option.
2. Invokes the root seeder (defaulting to `Database\Seeders\DatabaseSeeder`).
3. Wraps execution in a `Model::unguarded()` closure, temporarily lifting mass-assignment restrictions to allow direct property filling.

## Creating Production-Ready Laravel Seeders

For production environments, create dedicated seeders that leverage factories for realistic data while maintaining performance. The following example demonstrates a production seeder that disables model events for speed and creates essential admin users alongside a substantial product catalog:

```php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\User;
use App\Models\Product;

class ProductionDataSeeder extends Seeder
{
    /** Run the production data seeders. */
    public function run()
    {
        // Optional: run without model events for speed
        $this->withoutModelEvents(function () {
            // Create an admin user
            User::factory()->admin()->create([
                'email' => 'admin@example.com',
                'name'  => 'Production Admin',
            ]);

            // Seed a realistic catalog of products
            Product::factory()->count(500)->create();
        });
    }
}

```

Key implementation details:

- Extending `Seeder` provides access to `call()`, `withoutModelEvents()`, and container resolution.
- The `withoutModelEvents()` wrapper prevents observers from firing during bulk operations, mirroring the logic found in `Seeder::__invoke()`.
- Factories generate realistic data structures while maintaining referential integrity.

## Orchestrating Seeders with DatabaseSeeder

The `DatabaseSeeder` class serves as the entry point for all seeding operations. In [`database/seeders/DatabaseSeeder.php`](https://github.com/laravel/framework/blob/main/database/seeders/DatabaseSeeder.php), you can orchestrate multiple seeders while implementing environment-specific guards to prevent accidental production data overwrites:

```php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        // Common development seeders
        $this->call([
            UsersTableSeeder::class,
            PostsTableSeeder::class,
        ]);

        // Production‑only data – only run when a flag is passed
        if (app()->environment('production') && $this->option('with-production')) {
            $this->call(ProductionDataSeeder::class);
        }
    }

    /** Allow passing custom options from the Artisan command. */
    protected function option(string $key)
    {
        return $this->command?->option($key);
    }
}

```

This structure leverages the `call()` method's container resolution to instantiate and execute sub-seeders while tracking which have run to prevent duplicate execution.

## Running Seeders with Custom Flags

To execute your production seeder with custom flags, invoke the Artisan command with the specific class and your custom option:

```bash
php artisan db:seed --class=Database\\Seeders\\DatabaseSeeder --with-production

```

If you need to make `--with-production` a first-class option recognized by Artisan, extend the `SeedCommand` class in [`src/Illuminate/Database/Console/Seeds/SeedCommand.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Console/Seeds/SeedCommand.php) to register the option:

```php
// In src/Illuminate/Database/Console/Seeds/SeedCommand.php (excerpt)
protected function getOptions()
{
    return [
        ['class', null, InputOption::VALUE_OPTIONAL,
            'The class name of the root seeder',
            'Database\\Seeders\\DatabaseSeeder'],
        ['database', null, InputOption::VALUE_OPTIONAL,
            'The database connection to seed'],
        ['force', null, InputOption::VALUE_NONE,
            'Force the operation to run when in production'],
        // New custom flag
        ['with-production', null, InputOption::VALUE_NONE,
            'Run production‑only seeders'],
    ];
}

```

## Advanced Techniques for Production Data

### Dependency Injection in Seeders

Because `Seeder::resolve()` uses the Laravel IoC container, you can inject services directly into seeder constructors. This pattern is ideal for pulling real-world data from external APIs or legacy systems during production deployment:

```php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Services\ExternalDataImporter;

class ProductionDataSeeder extends Seeder
{
    public function __construct(protected ExternalDataImporter $importer) {}

    public function run()
    {
        $records = $this->importer->fetchLiveData();

        // Insert records directly (bypassing factories for exact mirrors)
        foreach ($records as $record) {
            \App\Models\RemoteItem::create($record);
        }
    }
}

```

### Silencing Output for Clean Deployments

When running seeders in automated deployment pipelines, use `callSilent()` instead of `call()` to suppress console output:

```php
$this->callSilent(ProductionDataSeeder::class);

```

This method leverages the same container resolution as `call()` but routes output through a silent resolver, keeping your deployment logs clean while maintaining full functionality.

## Summary

- **Laravel seeders** extend `Illuminate\Database\Seeder` to provide container-aware data population with built-in support for dependency injection and sub-seeder orchestration.
- The **`call()`** method resolves seeders through the IoC container and tracks execution to prevent duplicates, while **`callSilent()`** suppresses output for clean deployments.
- **`withoutModelEvents()`** disables observers during seeding, significantly improving performance when inserting large production datasets.
- **`DatabaseSeeder`** serves as the entry point, allowing environment-specific guards and custom command-line options to safely separate development and production data.
- Seeders support **constructor injection**, enabling integration with external APIs and legacy data importers for realistic production scenarios.

## Frequently Asked Questions

### Can I run seeders in production safely?

Yes, but only with explicit safeguards. Always check the application environment using `app()->environment('production')` before executing destructive operations, and use the `--force` flag with `php artisan db:seed` to confirm intent. Additionally, implement custom flags like `--with-production` to separate critical production data from development fixtures.

### How do I disable model events during seeding?

Wrap your database operations in the `withoutModelEvents()` method provided by the base `Seeder` class. This prevents observers and model events from firing during bulk inserts, significantly improving performance when seeding large production datasets. The functionality is implemented in [`src/Illuminate/Database/Seeder.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Seeder.php) within the `__invoke()` method.

### What's the difference between seeders and factories?

**Factories** define blueprints for generating fake data using the Faker library, while **seeders** are procedural classes that orchestrate the creation of database records. Seeders use factories via `Model::factory()->create()`, but they also handle raw inserts, external API calls, and complex relationships. According to the `laravel/framework` source code, seeders extend `Illuminate\Database\Seeder` and are resolved through the container, whereas factories use `Illuminate\Database\Eloquent\Factories\Factory`.

### How do I inject services into a seeder?

Add type-hinted dependencies to the seeder's constructor. Because `Seeder::resolve()` uses the Laravel IoC container to instantiate seeder classes, any interfaces or concrete classes you type-hint will be automatically injected. This pattern is ideal for importing production data from external APIs or legacy systems, as demonstrated in the `ProductionDataSeeder` example using `ExternalDataImporter`.