Pruning
Audit logs grow over time. Regulatory frameworks like GDPR encourage data minimization — keeping data only as long as it serves a legitimate purpose. The audit:prune command deletes audit logs older than a configurable retention period, keeping your database lean without manual intervention.
Basic Usage
php artisan audit:prune
By default, this deletes only light logs (where hash is NULL) older than the configured retention period (default: 90 days). Chained audit logs (with a hash) are preserved to maintain chain integrity. The command asks for confirmation before deleting.
Configuration
Set the default retention period in config/audit-chain.php:
'retention' => [ 'days' => 90, ],
Command Options
Custom Retention Period
Override the configured retention period with the --days flag:
# Keep only the last 30 days php artisan audit:prune --days=30 # Keep a full year php artisan audit:prune --days=365
Filter by Model Type
Prune logs for a specific model only, leaving other audit logs untouched:
php artisan audit:prune --type="App\Models\PageView"
This is useful when different models have different retention requirements — you might keep financial transaction logs for 7 years but prune page view logs after 30 days.
Including Chained Logs
By default, audit:prune only deletes light logs (no hash chain). To also prune chained audit logs, use the --include-chained flag. This requires the --force flag and displays a warning, because deleting chained logs affects chain verification:
php artisan audit:prune --days=365 --include-chained --force
When chained logs are pruned, the hash of the last deleted log is saved in the audit_chain_state.checkpoint_hash column. This checkpoint acts as the starting point for future chain verification — allowing audit:verify to pick up from where the pruned chain left off instead of failing on the first entry.
Force Mode
Skip the confirmation prompt with --force. Required when using --include-chained:
php artisan audit:prune --force
Combining Flags
php artisan audit:prune --days=30 --type="App\Models\PageView" php artisan audit:prune --days=365 --include-chained --force
How It Works
The command deletes records in chunks of 1,000 to avoid locking the database table for extended periods. This is safe for large tables with millions of audit logs — the command progressively deletes batches until all matching records are removed.
$ php artisan audit:prune --days=90 --no-interaction About to delete 15,234 audit log(s) older than 90 day(s). Deleted 1000 / 15234... Deleted 2000 / 15234... ... Deleted 15234 / 15234... Pruned 15234 audit log(s).
If no logs match the retention criteria, the command exits cleanly:
No audit logs older than 90 day(s) found.
Scheduling
For automated cleanup, schedule the prune command in routes/console.php:
Schedule::command('audit:prune')->daily();
See Scheduling for a complete cron setup.
Choosing a Retention Period
Your retention period depends on your compliance requirements:
| Regulation | Typical Retention |
|---|---|
| GDPR | As short as justifiable (data minimization principle) |
| SOX | 7 years |
| HIPAA | 6 years |
| PCI DSS | 1 year |
| NIS2 | No specific minimum, but sufficient for incident investigation |
Set retention.days to satisfy your most demanding obligation. Use the --type flag and scheduling to apply different retention periods to different models.