When it comes to Laravel packages that quietly power production‑grade apps, Spatie’s Laravel Activity Log sits near the top. It’s the invisible historian of your application — recording who did what, when, and to which model.
With version 5, Spatie has rewritten the internals to make activity logging faster, cleaner, and more expressive. The new release introduces PHP 8.4 + Laravel 12 support, merges traits for simplicity, adds activity buffering, and removes legacy batch logging.
Let’s unpack what makes this release special — and how you can use it to build audit trails that feel effortless.
⚙️ What the Activity Log Does
The package lets you record actions performed in your app — whether by users, jobs, or system processes.
At its simplest:
activity()->log('User updated profile');
But the real magic happens when you attach it to Eloquent models.
use Spatie\Activitylog\Models\Concerns\HasActivity;
class User extends Model
{
use HasActivity;
}
Now every create, update, or delete event automatically generates an activity record.
Each log entry includes:
- Description — what happened
- Causer — who performed the action
- Subject — which model was affected
- Properties — metadata (changed attributes, IP, etc.)
- Timestamps — when it happened
🧩 What’s New in v5
Spatie didn’t just bump versions — they rethought the architecture.
| Feature | Description | Benefit |
|---|---|---|
| Unified Trait | HasActivity replaces LogsActivity + CausesActivity. | Cleaner syntax, fewer imports. |
| Optional getActivitylogOptions() | Defaults applied automatically. | Less boilerplate for simple models. |
| Activity Buffering | Collects logs in memory, flushes after response. | Major performance boost for batch updates. |
| Default Causer | Activity::defaultCauser() sets a global causer. | Perfect for system‑wide or admin actions. |
| attribute_changes Column | Dedicated column for diffs. | Easier querying and cleaner schema. |
| Removed Batch System | LogBatch and related methods removed. | Simplifies schema and avoids unnecessary grouping. |
| Renamed Methods | activities() → activitiesAsSubject(), etc. | Consistent naming and clarity. |
🧠 The New HasActivity Trait
Previously, you had to juggle two traits:
use LogsActivity;
use CausesActivity;
Now, you simply use one:
use HasActivity;
This trait automatically handles both the subject (the model being logged) and the causer (the user or process performing the action).
It’s cleaner, easier to reason about, and works out of the box.
🧩 Automatic Model Logging
Once you add the trait, Spatie hooks into Eloquent’s lifecycle events.
use Spatie\Activitylog\Models\Concerns\HasActivity;
class Post extends Model
{
use HasActivity;
}
Now every create, update, or delete event is logged automatically.
You can customize what gets logged:
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults()
->logOnly(['title', 'content'])
->useLogName('post')
->setDescriptionForEvent(fn(string $eventName) => "Post has been {$eventName}");
}
🔍 Manual Logging with Context
Sometimes you want to log custom actions — not just model changes.
activity()
->performedOn($post)
->causedBy($user)
->withProperties(['via' => 'admin-panel'])
->log('Post updated');
This creates a record with full context:
- Causer:
$user - Subject:
$post - Properties:
['via' => 'admin-panel'] - Description: “Post updated”
🧩 Querying Activity Logs
The new API makes querying intuitive:
Activity::forSubject($post)->get();
Activity::causedBy($user)->get();
Activity::forEvent('updated')->get();
You can also chain filters:
Activity::forSubject($post)
->causedBy($user)
->where('log_name', 'post')
->latest()
->get();
⚡ Performance Boost with Buffering
One of the biggest changes in v5 is activity buffering.
Instead of writing each log entry immediately, Spatie now collects them in memory and flushes them in bulk after the response.
This drastically reduces database overhead for apps that log hundreds of events per request.
Enable buffering in your .env:
ACTIVITYLOG_BUFFER_ENABLED=true
You can also flush manually:
Activity::flushBuffer();
🧩 Default Causer
You can now set a global causer for all logs — useful for system‑wide actions or scheduled jobs.
Activity::defaultCauser(User::find(1)); // admin user
Every subsequent log will automatically use this causer unless overridden.
🧠 Schema Changes
The old JSON‑based properties column is now complemented by a dedicated attribute_changes column.
This column stores diffs between old and new values, making it easier to query specific changes.
Example:
SELECT * FROM activity_log WHERE attribute_changes->>'title' IS NOT NULL;
Cleaner, faster, and more database‑friendly.
🧭 Upgrade Guide
### 1. Update Dependencies
composer require spatie/laravel-activitylog:^5.0
### 2. Migrate Database
Remove batch_uuid, add attribute_changes:
php artisan migrate
### 3. Replace Traits
use HasActivity; // replaces LogsActivity + CausesActivity
### 4. Rename Methods
Update your code to use the new naming conventions.
### 5. Test Buffering
Enable buffering in staging before production.
🧩 Real‑World Use Cases
### 1. Audit Trails
Track every change made to critical models:
activity()
->performedOn($invoice)
->causedBy(auth()->user())
->log('Invoice marked as paid');
### 2. User Activity Tracking
Monitor user actions for analytics or compliance:
activity('login')
->causedBy($user)
->withProperties(['ip' => request()->ip()])
->log('User logged in');
### 3. System Events
Log background jobs or scheduled tasks:
Activity::defaultCauser(User::find(1)); // system user
activity()->log('Daily report generated');
### 4. Multi‑Tenant Apps
Attach tenant context to logs:
activity()
->performedOn($model)
->withProperties(['tenant_id' => tenant()->id])
->log('Record updated');
🧠 Advanced Configuration
### Custom Activity Model
You can extend the base model to add relationships or scopes:
class CustomActivity extends \Spatie\Activitylog\Models\Activity
{
public function scopeForAdmin($query)
{
return $query->where('causer_type', User::class)
->whereHas('causer', fn($q) => $q->where('is_admin', true));
}
}
Then register it in config/activitylog.php:
'activity_model' => App\Models\CustomActivity::class,
### Custom Log Names
Group logs by context:
activity()->useLogName('orders')->log('Order shipped');
### Custom Properties
Attach structured metadata:
activity()
->withProperties([
'old_status' => 'pending',
'new_status' => 'shipped',
'changed_by' => auth()->id(),
])
->log('Order status changed');
🧩 Testing and Debugging
Spatie’s package integrates beautifully with Pest PHP and PHPUnit.
it('logs model updates', function () {
$post = Post::factory()->create(['title' => 'Old']);
$post->update(['title' => 'New']);
expect(Activity::forSubject($post)->count())->toBeGreaterThan(0);
});
🎯 Final Thoughts
Spatie’s Laravel Activity Log v5 is more than just a version bump — it’s a thoughtful re‑architecture that makes logging feel natural instead of burdensome. By merging traits into a single HasActivity, introducing buffered logging for performance, and simplifying configuration, v5 ensures that developers can focus on building features while still maintaining a reliable audit trail.
For teams working on compliance‑heavy applications, multi‑tenant SaaS platforms, or simply wanting visibility into user actions, this release delivers both clarity and speed. The addition of the attribute_changes column makes querying diffs straightforward, while the new default causer functionality reduces repetitive boilerplate.
Ultimately, v5 embodies the philosophy that good logging should be invisible until you need it — and invaluable when you do. If you’re running Laravel 12 or higher, upgrading to Spatie’s Activity Log v5 is a no‑brainer. It’s the easiest way to ensure that every change on your Eloquent models is captured, contextualized, and ready for analysis.
