Active Record Pattern
Also Known As
Active Record
Eloquent
ORM Active Record
TL;DR
A design pattern where a database row is wrapped in an object that includes both the data and the persistence logic — the object knows how to save, update, and delete itself.
Explanation
Active Record (Martin Fowler, PoEAA) places persistence logic inside the domain object: User::find(1), $user->save(), $user->delete(). The object maps directly to a database row. Advantages: simple, low boilerplate, excellent for CRUD applications. Disadvantages: couples domain logic to persistence, makes unit testing without a database hard, violates SRP, and becomes unwieldy for complex domain logic. Laravel's Eloquent, Ruby on Rails, Django ORM are all Active Record implementations.
Common Misconception
✗ Active Record is always an anti-pattern — it is entirely appropriate for simple CRUD applications and rapid development; the Repository pattern adds complexity only justified by complex domain logic.
Why It Matters
Choosing Active Record for a complex domain with rich business logic leads to God Objects that are impossible to test; choosing Repository for a simple CRUD API adds unnecessary abstraction layers.
Common Mistakes
- Business logic inside Active Record models — they become unmaintainable God Objects.
- Unit testing Active Record models without a database — requires database setup, making tests slow.
- N+1 queries from lazy loading — always eager-load relationships with with() in Eloquent.
- Using Active Record when a complex aggregate requires multiple tables — use Repository instead.
Avoid When
- Domain logic is complex — mixing business rules with persistence makes both harder to test and change.
- You need to support multiple storage backends or swap databases; the object is tightly coupled to one schema.
- Writing unit tests that should not touch a database — the persistence coupling forces slow integration tests.
When To Use
- Simple CRUD-heavy apps where domain logic is thin and co-locating persistence with data is acceptable.
- Rapid prototyping or internal tools where the overhead of a separate data mapper is not justified.
- Teams already using a framework (Laravel Eloquent, Rails) where Active Record is the idiomatic default.
Code Examples
💡 Note
The bad example shows an Active Record model handling validation, payment, and email — three concerns that should live elsewhere once the domain grows.
✗ Vulnerable
// Active Record model doing too much:
class Order extends Model {
public function process(): void {
// Validation, pricing, inventory, emails all in one class
if ($this->total > $this->customer->credit_limit) throw new Exception();
$this->status = 'processing';
$this->save();
$this->inventory->decrement($this->items);
Mail::send(new OrderConfirmation($this));
// Untestable without DB, email service, inventory service
}
}
✓ Fixed
// Active Record for simple CRUD — appropriate:
class User extends Model {
protected $fillable = ['name', 'email'];
protected $hidden = ['password'];
public function orders(): HasMany {
return $this->hasMany(Order::class);
}
}
// Simple — maps rows to objects, relationships via ORM
// Complex domain logic extracted to dedicated service classes
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
16 Mar 2026
Edited
31 Mar 2026
Views
29
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Perplexity 8
Amazonbot 6
ChatGPT 3
Unknown AI 3
Google 3
Ahrefs 1
Also referenced
How they use it
crawler 23
crawler_json 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟡 Medium
⚙ Fix effort: Medium
⚡ Quick Fix
Keep business logic out of Active Record models — use service classes or domain objects for logic, and models only for persistence; avoid fat models with 50+ methods
📦 Applies To
PHP 5.0+
web
cli
queue-worker
laravel
eloquent
🔗 Prerequisites
🔍 Detection Hints
Eloquent model with business logic methods sending emails making HTTP calls calculating prices
Auto-detectable:
✗ No
phpstan
phpcs
⚠ Related Problems
🤖 AI Agent
Confidence: Low
False Positives: High
✗ Manual fix
Fix: High
Context: Class
Tests: Update