In a Laravel model factory, what is the difference between make() and create(), and what does each return?
answer
- in memory vs in the table
- create() = make() then save()
- count() switches to a Collection
- afterMaking vs afterCreating
- nested parent factories still insert
basics
~20 smake() builds model instances from the factory's definition() without saving them; create() builds them the same way and then persists each one with save(). Both return a single model, or an Eloquent Collection once count() is set.
solid answer
~40 s`make()` returns a fresh model built from `definition()` plus any states, with `exists` false and no primary key; it runs the factory's `afterMaking` callbacks. `create()` calls `make()` first, then `save()`s each instance, builds any `has()` children and runs the `afterCreating` callbacks. Without `count()` both return one model; with `count(n)` they return an Eloquent `Collection`, and `makeOne()` / `createOne()` force a single model. Factories build models with mass assignment protection switched off, so `$fillable` does not filter factory attributes. The trap: `make()` is not guaranteed to be query-free, because a parent factory assigned to a foreign key in `definition()` (`'doctor_id' => Doctor::factory()`) is created and saved so the unsaved child can hold a real key.
code
php · 13 lines<?php
use App\Models\Appointment;
// Unsaved: exists === false, no id
$draft = Appointment::factory()->make(['status' => 'booked']);
// Saved: one INSERT per model, afterCreating callbacks run
$booked = Appointment::factory()->count(3)->create();
$draft->exists; // false
$booked->first()->exists; // true
$booked instanceof \Illuminate\Database\Eloquent\Collection; // truego deeper
Recall that make() builds unsaved models and create() saves them with save(), and that count() turns the result into an Eloquent Collection.
Explain that create() is make() plus save(), which callbacks run in each, and why nested parent factories in definition() insert rows even under make().
Show judgement about seeding cost and side effects: create() fires model events and one INSERT per row, so choose make(), createQuietly() or withoutParents() deliberately.
Frame factories as a shared team asset: conventions for what definition() may create implicitly decide how fast and predictable every seeder built on them stays.
## What a model factory is A **model factory** is a class in `database/factories` that extends `Illuminate\Database\Eloquent\Factories\Factory` and describes how to build a plausible Eloquent model. Its one required method is `definition()`, which returns an array of default attribute values, usually generated with the `fake()` helper (a Faker generator). A model reaches its factory through the `HasFactory` trait: `Appointment::factory()` resolves `Database\Factories\AppointmentFactory` by naming convention, or the class named by a `#[UseFactory]` attribute on the model. `php artisan make:factory AppointmentFactory` generates the class with an empty `definition()`. From there, every call on the factory (`count()`, `state()`, `for()`, `has()`) returns a **new, immutable factory instance**; nothing is built until you call a terminal method such as `make()`, `create()` or `raw()`. ## make(): build in memory `make()` does four things: 1. Evaluates `definition()` for each model, then layers any states and the attributes you passed on top. 2. Instantiates the model class with those attributes, inside `Model::unguarded()`, so `$fillable` and `$guarded` do not filter anything. 3. Runs every `afterMaking` callback registered on the factory. 4. Returns the model, or an Eloquent `Collection` of models when `count()` was set. The models are **not saved**: `$model->exists` is `false`, and an auto-increment `id` is absent. Children declared with `has()` are not built at all, and `afterCreating` callbacks do not run. ## create(): make, then save `create()` calls `make()` internally, so `afterMaking` callbacks run here too. Then it: - calls Eloquent's `save()` on each instance, which issues one `INSERT` and fires the usual model events; - creates each instance's children declared with `has()` / `hasAttached()`, now that the parent has a key; - once every instance is stored, runs the `afterCreating` callbacks for each saved model. `createQuietly()` does the same inside `Model::withoutEvents()`. ## Return shapes at a glance | Call | Returns | Touches the table? | |---|---|---| | `Appointment::factory()->make()` | one `Appointment`, unsaved | only for nested parent factories | | `Appointment::factory()->count(3)->make()` | `Collection` of 3 unsaved | only for nested parent factories | | `Appointment::factory()->create()` | one saved `Appointment` | yes | | `Appointment::factory()->count(3)->create()` | `Collection` of 3 saved | yes | | `Appointment::factory()->count(3)->makeOne()` | one unsaved model (count ignored) | only for nested parents | | `Appointment::factory()->raw()` | attribute array | only for nested parents | `count(0)` returns an empty collection rather than null. ## The traps interviewers probe - **make() can still insert rows.** If `definition()` contains `'doctor_id' => Doctor::factory()`, the factory resolves that nested factory by calling `create()` on it, because an unsaved appointment still needs a real doctor key. Use `withoutParents()` or pass an existing id to keep `make()` in memory. - **Mass assignment is off.** A factory attribute that is not in `$fillable` is still set; this is deliberate, and it means a factory cannot be used to check your `$fillable` list. - **Overrides win.** `create(['status' => 'cancelled'])` is applied as the last state, after `definition()` and any named states. - **Return type depends on count().** Code that calls `->id` on the result breaks when someone adds `count(2)` upstream; `createOne()` makes the single-model intent explicit. ## The other terminal methods `make()` and `create()` have a small family of siblings worth recognising: - **`makeOne()` / `createOne()`** reset the count to null first, so they always return a single model even if `count()` was chained earlier; - **`makeMany(3)` / `createMany(3)`** return a collection; `createMany()` also accepts a list of attribute arrays, one per model, such as `createMany([['status' => 'booked'], ['status' => 'no_show']])`; - **`raw()`** returns the expanded attribute array (or a list of arrays with `count()`) without instantiating a model, which is handy for building a request payload that matches the factory; - **`lazy()`** returns a closure that calls `create()` when invoked, deferring the write until something actually needs the row. All of them share the same definition, states and overrides, so the only question is what shape you need back and whether a row must exist. ## Choosing between them Reach for `make()` when you need an object with realistic attributes but no row: building a view model, computing a value, or passing a model to code that saves it itself. Reach for `create()` when the record must exist for a query, a foreign key or a relationship to work. For a demo hospital database the seeder uses `create()`; for an in-memory `Appointment` whose price you want to calculate, `make()` avoids the write.
- Which factory callbacks run when you call create(), and in what order?`create()` calls `make()` first, so every `afterMaking` callback runs as the instances are built. Once the models are saved and their `has()` children created, the `afterCreating` callbacks run for each saved model. `make()` alone runs only the `afterMaking` callbacks.
- Why can AppointmentFactory::make() insert a doctor row, and how do you stop it?When `definition()` assigns `Doctor::factory()` to `doctor_id`, the factory creates that doctor so the key is real, even inside `make()`. Chaining `withoutParents()` leaves such keys null, and passing an existing id, a model, or using `recycle()` reuses rows instead of inserting new ones.
- Does $fillable restrict what a factory can set on a model?No. Factories build instances inside `Model::unguarded()`, so every attribute from `definition()`, states and overrides is set regardless of `$fillable` or `$guarded`. That is why a factory cannot be used to verify your mass-assignment rules.
saying these in an interview costs you the question
- make() never runs a query, whatever definition() contains
- create() skips afterMaking callbacks and runs only afterCreating
- make() returns a plain attribute array rather than a model
- count(3)->create() returns an array of models
- Factories respect $fillable, so unlisted attributes are dropped