Configure AuditTrailBundle
Create config/packages/audit_trail.yaml and configure only the features
your application needs. The database transport is the default baseline.
Baseline Config
# config/packages/audit_trail.yaml
audit_trail:
enabled: true
table_prefix: ''
table_suffix: ''
timezone: 'UTC'
ignored_properties: ['updatedAt', 'updated_at']
ignored_entities: []
retention_days: 365
track_ip_address: true
track_user_agent: true
enable_hard_delete: true
enable_soft_delete: true
soft_delete_field: 'deletedAt'
cache_pool: null
audited_methods: ['GET']
collection_serialization_mode: 'lazy'
max_collection_items: 100
table_prefixandtable_suffixmay contain only letters, numbers, and underscores, and cannot start with a digit.soft_delete_fieldshould be a nullable timestamp-like field, such asdeletedAtorarchivedAt.- Use mapped entity classes in
ignored_entities; the bundle resolves proxies and lazy subclasses back to the mapped class. - Set
cache_poolto a PSR-6 pool when access-audit cooldowns must survive beyond the current request.
Collection And Queue Limits
audit_trail:
collection_serialization_mode: 'lazy' # lazy, ids_only, or eager
max_collection_items: 100
queue_limits:
scheduled_audits: 1000
pending_audit_plans: 1000
pending_deletions: 1000
Keep collection_serialization_mode on lazy unless your audit history
must include relation item IDs. Use ids_only or eager deliberately on
entities where the extra Doctrine work is acceptable.
If a collection exceeds max_collection_items, the stored value is truncated to a
marker payload with _truncated, _total_count, and
_sample keys instead of writing an unbounded relation snapshot.
Database Transport
audit_trail:
transports:
database:
enabled: true
async: false
Use synchronous database transport when you want local persistence with no extra package. Use
async: true only after installing and configuring Symfony Messenger.
Queue Transport
# config/packages/audit_trail.yaml
audit_trail:
transports:
queue:
enabled: true
bus: 'messenger.bus.default'
# Optional: adds an ApiKeyStamp to queued audit messages.
api_key: '%env(AUDIT_QUEUE_API_KEY)%'
# config/packages/messenger.yaml
framework:
messenger:
transports:
audit_trail: '%env(MESSENGER_TRANSPORT_DSN)%'
HTTP Transport
audit_trail:
transports:
http:
enabled: true
endpoint: 'https://audit-service.internal/api/logs'
headers:
Authorization: 'Bearer %env(AUDIT_HTTP_TOKEN)%'
timeout: 10
The HTTP endpoint must start with http:// or https://. Plain HTTP is
allowed only in the dev environment; use HTTPS in production. Install
symfony/http-client before enabling this transport.
Integrity Signing
audit_trail:
integrity:
enabled: true
secret: '%env(string:AUDIT_INTEGRITY_SECRET)%'
algorithm: 'sha256'
When integrity is enabled, stored audit logs can be verified later and HTTP or queue payloads are signed for transport authenticity. The bundle expects the secret to be configured as a Symfony env placeholder.
EasyAdmin Options
audit_trail:
easyadmin:
permission: 'ROLE_ADMIN'
export_limit: 50000
The EasyAdmin export limit keeps browser-triggered downloads bounded. Use
audit:export for larger or full-history exports.
In 4.1+, the old root-level admin_permission and
admin_export_limit options are deprecated. Use the nested
easyadmin options shown above.
Transaction Safety
audit_trail:
defer_transport_until_commit: true
fail_on_transport_error: false
fallback_to_database: true
| Goal | Useful Settings |
|---|---|
| Default write performance | defer_transport_until_commit: true |
| Strict database audit path | database.async: false and fail_on_transport_error: true
|
| External transport with local safety net | fallback_to_database: true with database transport enabled |
HTTP and queue transports are deferred-phase transports. Setting
defer_transport_until_commit: false does not move them into Doctrine's
onFlush transaction window.
When HTTP or queue transport is enabled and these flags are not set explicitly, the bundle treats
remote delivery as strict by default: fail_on_transport_error becomes
true and fallback_to_database becomes false. Set both
values deliberately for your durability model.
- At least one transport must be enabled when
audit_trail.enabledistrue. - Enabling async database or queue transport without
symfony/messengerthrows a clear container-buildLogicException. - Enabling HTTP transport without
symfony/http-clientthrows a clear container-buildLogicException. - Boolean or status-based soft-delete markers need custom restore handling; the built-in restore flow clears a nullable timestamp-like field.