TeachyLeaf library

What are you looking for?

Search practical tutorials and browser-based tools.

Laravel · Database · Beginner

Laravel database seeding and factories: add safe sample data

Follow TeachyLeaf’s real seeders and factories to see how repeatable catalog data differs from disposable test records—and why environment checks matter.

Who this is for: Laravel beginners who have seen migrations and want to understand how example records are created.

What you will learn: what seeders and factories do, how TeachyLeaf's default and catalog seeders differ, how repeatable records are matched, and how to keep sample data away from production.

Prerequisites: Basic Eloquent models, migrations, and Artisan commands.

Tested environment: Laravel Framework 13.16.1 and PHP 8.4.15. Feature tests use SQLite in memory. Never point a local seeding command at a production database unless the operation has been reviewed and is explicitly intended.

Seeder versus factory

A seeder is an entry point for inserting or updating data. A model factory describes how to construct model attributes, often using Faker to generate varied sample values. A seeder can call factories, define fixed records, or combine both approaches.

TeachyLeaf has a default DatabaseSeeder, a separate TutorialSeeder, and model factories for users and blog posts. These have different purposes and are not interchangeable.

What the default seeder creates

The current DatabaseSeeder creates a user with a fixed test identity and asks the blog factory for six records:

User::factory()->create([
    'name' => 'Test User',
    'email' => 'test@example.com',
]);

Blog::factory(6)->create();

The user factory hashes a fixed development password by default. The blog factory generates titles, excerpts, content, categories, authors, dates, and statuses; a generated post can have the status Published. This data is useful for local development, but it is not reviewed editorial content and the test account is not a production administrator.

Do not run the default sample seeder on production

Do not run php artisan db:seed or php artisan migrate --seed against TeachyLeaf's production database in its current form. The default seeder creates a test account with a predictable factory password and inserts random blog content that may be marked Published. That could create an unsafe account or expose fake posts to visitors.

Before running any seeder, verify the active application environment and database target. Treat seeders as database writes: review their code, understand whether they insert, update, or delete, keep a restorable backup where appropriate, and never rely on the command name alone as a safety barrier.

Factories make example records

The blog factory returns a set of attributes for each model instance. A shortened version of its behavior is:

return [
    'title' => $title,
    'slug' => $slug,
    'excerpt' => $this->faker->paragraph(2),
    'content' => $this->faker->paragraphs(6, true),
    'category' => $this->faker->randomElement([
        'Electronics',
        'Programming',
        'Career',
        'Tutorial',
    ]),
    'status' => $this->faker->randomElement([
        'Published',
        'Draft',
        'Archived',
    ]),
];

For a test, a factory can create one record or a requested number of records:

$draft = Blog::factory()->create([
    'status' => 'Draft',
]);

$samplePosts = Blog::factory(6)->create();

Overrides make a particular test case explicit. The six generated posts are randomized, so their statuses and content are not guaranteed to match a fixed expected list. Tests that depend on a specific result should set the fields they assert rather than relying on Faker's random choices.

The catalog seeder uses an upsert-style pattern

TutorialSeeder defines known tutorial and tool metadata and finds each row by its slug. It creates a row when none exists, or updates a matching row with the seeder's metadata:

$tutorial = Tutorial::firstOrNew(['slug' => $item['slug']]);

if ($tutorial->exists && $tutorial->published_at !== null) {
    $item['published_at'] = $tutorial->published_at;
}

$tutorial->fill($item)->save();

This avoids creating a second row for a slug when the seeder runs again. Existing publication dates are preserved; a new record gets the seeder's current publication date. Other fields on matching records are updated to the values in the seeder, so review those values first if catalog metadata has been edited directly in production.

The default DatabaseSeeder does not call TutorialSeeder. Running php artisan db:seed runs the default seeder, not every seeder file. A specific seeder can be selected with --class, but that command still writes to whichever database the application is configured to use.

How to seed a disposable local database

For a local database that you are prepared to populate, inspect the target environment and then run the default seeder:

php artisan about --only=environment
php artisan db:seed

The first command helps inspect the application environment; it does not prove that the configured database is disposable. Confirm the connection and database name separately before writing data. If the goal is to populate only the tutorial catalog, Laravel supports selecting that seeder:

php artisan db:seed --class=TutorialSeeder

Do not use destructive reset commands such as migrate:fresh --seed on any database containing data you need: migrate:fresh drops all tables before rebuilding them.

Practice: decide whether the command is safe

You are connected to the public site database and want to add one reviewed article. The default seeder also creates a test user and six randomly generated blog posts. Should you run php artisan db:seed?

Show the answer

No. The default seeder is for example data and is unsafe for this production database. Use the site's reviewed publishing workflow, or design a narrowly scoped, reviewed data change for the intended environment. Never run the default sample seeder just to add one article.

References

Continue learning

Start with the migration lesson to understand schema changes, then see how tests use factories in the Laravel feature testing guide. For the production data flow, read the Eloquent blog query lesson.