If you are coming from Laravel and trying out Prisma for the first time, the two ORMs feel surprisingly different even though they do the same job. This post walks through how each one thinks about your data, why the differences matter, and how to pick a mental model that fits the tool you are using.
The headline difference: where the truth lives
This is the single biggest thing to internalize.
Laravel Eloquent stores the truth in migration files.
You write migrations one at a time. Each migration is a step. The current shape of your database is the result of running all of them in order. The model class itself does not list your columns. It lists relations, accessors, mutators, and what is fillable, but if you want to know what columns the users table has, you read the latest migration that touched it.
Prisma stores the truth in schema.prisma.
You declare the whole shape of your database in one file. Models, fields, types, relations, indexes, all of it. When you run prisma migrate dev, Prisma compares the schema to the database and generates a migration that closes the gap. The migration files exist, but they are an output, not the source.
Laravel is history based. Prisma is state based.
Laravel mental model:
migrations are the source -> running them produces the database
Prisma mental model:
schema is the source -> Prisma generates migrations from it
Once that clicks, most of the other differences make sense.
The perfectionist take
If you are someone who likes a single clean view of your data, Prisma feels great. You open schema.prisma and you see everything: every model, every column, every relation, in one file. There is no hunting through dated migration files to figure out what the current shape is. There is no risk of the model class drifting from the migration. The schema file is the answer.
In Laravel, you can run into situations like this:
- You add a
statuscolumn in a new migration. - You forget to add
statusto the$fillablearray on the model. - Now
User::create(['status' => 'active'])silently does not save the field.
That kind of drift cannot happen in Prisma. The schema file is the only place you describe a column, and the generated client knows about every field automatically. There is nothing to remember to update on a separate model class.
The flip side: merge conflicts
Here is the trade off that bites teams using Prisma. Because everything lives in one file, that one file is a hot spot. If two developers add models on the same day, both branches edit schema.prisma, and you get a merge conflict.
Laravel rarely has this problem. Each migration is its own dated file. Two developers can add migrations in parallel and Git just stacks them. The order of files might shuffle a bit, but you usually do not have to manually resolve text conflicts in the same file.
So:
| Topic | Laravel Eloquent | Prisma |
|---|---|---|
| Where the truth lives | Migration files | schema.prisma |
| Risk of model drifting | Real (model class vs migrations) | None (one source) |
| Merge conflicts in schema work | Rare | Common in busy teams |
| Reading current state | Read the latest migration | Read the schema file |
| Style | Imperative, history of changes | Declarative, snapshot of the world |
Neither is wrong. They are different bets about where pain should land.
How migrations feel different
In Laravel, a migration is something you write by hand:
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('body');
$table->timestamps();
});
You wrote that file. You own it. When you change the schema, you write another migration that adds or alters columns.
In Prisma, you write the new shape into the schema file:
model Post {
id Int @id @default(autoincrement())
title String
body String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Then you run prisma migrate dev --name add_posts, and Prisma writes the SQL migration for you. You almost never edit migration files by hand. They are an output.
This is freeing once you trust it, and a little uncomfortable when you do not. If you want full control over the SQL, Laravel feels safer. If you want to never write ALTER TABLE again, Prisma feels like a gift.
How models feel different
In Laravel, the model class is where logic lives:
class Post extends Model
{
protected $fillable = ['title', 'body'];
public function author()
{
return $this->belongsTo(User::class);
}
}
It knows about relations, accessors, scopes, events, casts. The columns are implied from the migration plus the database itself.
In Prisma, the model is just a shape declaration. There is no class to extend, no custom methods, no scopes:
model Post {
id Int @id @default(autoincrement())
title String
body String
authorId Int
author User @relation(fields: [authorId], references: [id])
}
Behavior lives in your application code, separate from the data definition. This is intentional. Prisma wants the schema to describe data and only data. Logic goes in services, controllers, repositories, wherever your architecture puts it.
If you love fat models with rich behavior, Laravel will feel more natural. If you prefer skinny data and behavior in plain functions, Prisma will feel cleaner.
How to pick a mental model
When working in Laravel, think:
"Each change to the database is a migration. The model class describes how to interact with the rows, not what the rows look like."
When working in Prisma, think:
"There is one schema file. I edit it to describe what the database should look like. Prisma figures out how to get there."
Trying to use the wrong mental model is where most frustration comes from. Writing Prisma like Laravel makes you fight the tool. Writing Laravel like Prisma misses the point of migrations as an audit trail.
Tiny rules of thumb
- In Laravel, never edit a migration after it is shipped. Write a new one.
- In Prisma, never edit a generated migration file. Change the schema instead and let Prisma rewrite it.
-
In Laravel, keep the model and migration in sync mentally. Always check
$fillableand casts when you add columns. -
In Prisma, when you start a new feature on a busy team, pull the latest
mainbefore editing the schema, just like you would for apackage.json.
Final thought
Laravel's Eloquent and Prisma are not really competing in style, they are competing in philosophy. Laravel says "I will track every change you make." Prisma says "Tell me what you want, I will make it happen." Both are good answers. The right one depends on whether you would rather hold the history yourself or trust the tool to derive it.
If you came from Laravel and are giving Prisma an honest try, the perfectionist in you will probably enjoy having the schema in one place. Just be ready to coordinate a little more carefully when teammates are also touching that file.
Top comments (0)