php 56 lines · 9 steps

Building blog test data with Laravel factories

A database seeder wires users, posts, comments, and categories into a realistic graph using nested factory relationships.

Explained by highlit
1<?php
2 
3namespace Database\Seeders;
4 
5use App\Models\Category;
6use App\Models\Comment;
7use App\Models\Post;
8use App\Models\User;
9use Illuminate\Database\Seeder;
10 
11class BlogSeeder extends Seeder
12{
13 public function run(): void
14 {
15 $categories = Category::factory()
16 ->count(5)
17 ->create();
18 
19 $authors = User::factory()
20 ->count(10)
21 ->has(
22 Post::factory()
23 ->count(8)
24 ->recycle($categories)
25 ->state(fn () => ['status' => 'published'])
26 ->has(Comment::factory()->count(3), 'comments')
27 ->afterCreating(function (Post $post) {
28 $post->categories()->attach(
29 Category::inRandomOrder()->take(2)->pluck('id')
30 );
31 }),
32 'posts'
33 )
34 ->create();
35 
36 User::factory()
37 ->unverified()
38 ->count(3)
39 ->has(Post::factory()->count(2)->draft(), 'posts')
40 ->create();
41 
42 Comment::factory()
43 ->count(40)
44 ->flagged()
45 ->recycle($authors)
46 ->for(Post::inRandomOrder()->first())
47 ->create();
48 
49 User::factory()
50 ->admin()
51 ->create([
52 'name' => 'Editor In Chief',
53 'email' => 'editor@example.test',
54 ]);
55 }
56}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Nested factory calls with has() let you build an entire relationship tree in one create() statement.
  2. 2recycle() reuses existing models instead of spawning new ones, keeping foreign keys pointing at a shared pool.
  3. 3Factory states and callbacks like afterCreating() attach extra data such as pivot rows once records exist.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building blog test data with Laravel factories — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code