Rails 8.2 makes enqueue_after_transaction_commit the default
· 3 min read
Rails 7.2 introduced enqueue_after_transaction_commit to prevent race conditions when jobs are enqueued inside database transactions. However, it required explicit opt-in. Rails 8.2 flips the default. Jobs are now automatically deferred until after the transaction commits.
The Problem with Opt-In
With the opt-in approach in Rails 7.2, teams had to remember to enable the feature:
config.active_job.enqueue_after_transaction_commit = :default
Or configure it per-job:
class WelcomeEmailJob < ApplicationJob
self.enqueue_after_transaction_commit = :always
end
This created inconsistency. Some jobs would be transaction-aware, others would not. The safer behavior required explicit action.
Rails 8.2 Changes the Default
PR #55788 changes this. When you upgrade to Rails 8.2 and run load_defaults "8.2", jobs are automatically deferred until after the transaction commits.
def create
User.transaction do
user = User.create!(params)
WelcomeEmailJob.perform_later(user) # Deferred until commit
end
end
No configuration needed. The job waits for the transaction to complete before being dispatched to the queue.
Opting Out
If you need immediate enqueueing for backward compatibility or specific use cases, you have two options.
Global configuration:
config.active_job.enqueue_after_transaction_commit = false
Per-job configuration:
class TimeStampedJob < ApplicationJob
self.enqueue_after_transaction_commit = false
end
Why the Global Config Was Restored
The global configuration option has an interesting history. It was deprecated and removed in Rails 8.1. The team initially wanted each job to declare its own preference. However, changing the default behavior without a global opt-out would break existing applications.
The PR restored the global configuration specifically to allow apps upgrading to Rails 8.2 to maintain their existing behavior without modifying every job class.
When This Matters
The new default primarily affects jobs enqueued to external queues like Redis (Sidekiq, Resque). If you use a database-backed queue like Solid Queue or GoodJob with the same database, your jobs are already part of the same transaction.
Jobs that do not depend on transaction data can still be configured for immediate enqueueing if needed.
Conclusion
Rails 8.2 makes the safer behavior the default. Jobs enqueued inside transactions automatically wait for the commit, eliminating a common source of race conditions without requiring explicit configuration.
References
- Pull Request #55788 making this the default
- Pull Request #51426 introducing the feature in Rails 7.2
- Rails 7.2 enqueue_after_transaction_commit - detailed explanation of the feature