Moving from GoodJob to Solid Queue — with a Surprise 💥
Edu Depetris
- Nov 06, 2025- Rails 8.1
- Solid Queue
- Good Job
- Migration
TL;DR
I tried moving from GoodJob to SolidQueue on my tiny 512 MB Heroku dyno. It worked… but my app ran out of memory fast. SolidQueue looks great for future setups (especially once async mode lands), but for now, GoodJob in async mode is still the best choice for small, memory-limited environments.
As part of our Rails 8.1 migration, we’re moving our background job system from GoodJob to Solid Queue.
Why the move
Solid Queue is now the new default Active Job backend in Rails 8.1. It’s lighter, simpler to maintain, and integrates deeply with the framework.
Considerations and restrictions for our migration:
UI Dashboard
GoodJob includes a great web dashboard, so to keep that visibility we’ll install and configure Mission Control, which works seamlessly with Solid Queue.
Running Solid Queue on Postgres
We’ll run Solid Queue using our existing Postgres database. This simplifies setup and reduces our Heroku costs since we won’t need an additional DB instance.
Incremental adoption
We’ll start by running a few background jobs with Solid Queue in production. Once everything looks stable, we’ll migrate all jobs over completely.
Let’s begin by installing Solid Queue in our freshly upgraded Rails 8.1 app.
Step 1: Add Solid Queue to the Gemfile
Add the gem to your Gemfile and run bundle install:
gem "solid_queue", "~> 1.2"$ bundle install
Step 2: Install Solid Queue
Once the gem is installed, run the Solid Queue installer:
$ solid_queue:installThis will create the necessary initializer, database migrations, and configuration files.
Step 3: Database Configuration
Because we’re going to run Solid Queue using the same application database, we won’t need multiple databases. This means your
database.yml file no longer needs separate configurations for primary and queue databases.- Generate a new migration for Solid Queue:
bin/rails g migration add_solid_queue
- Copy the contents of db/queue_schema.rb into the new migration
class AddSolidQueue < ActiveRecord::Migration[8.1] def change create_tble "solid_queue_blocked_executions", force: :cascade do |t| t.bigint "job_id", null: false ... ... REST OF THE CODE end end
- Run the migrations
bin/rails db:migrate
Step 4: Production Configuration
Before deploying, make sure to restore the Active Job queue adapter to its previous value — in this case, GoodJob.
We don’t want to start using Solid Queue in production just yet.
We don’t want to start using Solid Queue in production just yet.
Open your
config/environments/production.rb file and check the following:- Set the queue adapter back to GoodJob:
config.active_job.queue_adapter = :good_job - Because we’re now using a single database, comment out or remove this line:
# config.solid_queue.connects_to = { database: { writing: :queue } }
This ensures your app continues running smoothly with GoodJob while Solid Queue is fully set up and tested.
Step 5: Mission Control UI Dashboard
Now, let’s move on to Mission Control, the new UI dashboard that works with Solid Queue.
We’ll install and configure it to run alongside GoodJob during the migration period.
- Add the gem to your Gemfile and run bundle install:
gem "mission_control-jobs" - Restrict access to authenticated users
We’ll mount the dashboard only for logged-in admins.
In this example, the app uses Devise, so we’ll mount both GoodJob and Mission Control under authenticated routes:authenticate :admin do mount GoodJob::Engine => "admin/good_job" mount MissionControl::Jobs::Engine, at: "admin/jobs" end
- Disable default Basic Auth
Mission Control comes with Basic Auth enabled by default. Since we’re already using Devise authentication, let’s disable it. Update yourconfig/application.rbfile:# Mission Control Jobs: Disable HTTP Basic Auth in favor of Devise authentication config.mission_control.jobs.http_basic_auth_enabled = false
- Configure the adapter
By default, Mission Control assumes you’re using GoodJob (default active_job queue).
We need to tell it to use Solid Queue when rendering the /admin/jobs dashboard.# config/application.rb config.mission_control.jobs.adapters = [:solid_queue]
Step 6: Testing Solid Queue in Production
Up to this point, we’ve made solid progress and we’re ready to test Solid Queue in production.
We’ll take a progressive approach — first by running a simple test job to make sure everything works as expected.
Let’s create a dedicated job that will:
- Log information so we can confirm Solid Queue is running.
- Raise an exception in our error tracking tool (Rollbar, in this case).
Generate the job with:
bin/rails g job test_solid_queue
Then edit the generated job:
class TestSolidQueueJob < ApplicationJob
queue_as :default
self.queue_adapter = :solid_queue
def perform(*args)
Rails.logger.info("*" * 20)
Rails.logger.info("TestSolidQueueJob executed with arguments: #{args.inspect}")
Rails.logger.info("*" * 20)
if args.include?("fail")
Rails.logger.error("Failing as requested")
raise "Intentional failure for testing Solid Queue error handling"
end
end
endNow we’re ready to deploy and test our setup.
Running Solid Queue with Puma
We’ll run Solid Queue using the Puma plugin.
To enable it in Heroku, set the following environment variable:
Verify Everything Works
SOLID_QUEUE_IN_PUMA=1
Verify Everything Works
Once deployed, open your production console and run:
TestSolidQueueJob.perform_later("fail")
If everything is configured correctly, you should see:
- Logs in your Heroku console from the job execution.
- An error reported to Rollbar (because of the intentional failure).
- The job visible in the Mission Control dashboard under Solid Queue.
Step 7: Fully Migrate to Solid Queue
Once you’ve confirmed everything works as expected, completing the migration is simple. Just update your Active Job queue adapter:
# config/environments/production.rb
config.active_job.queue_adapter = :solid_queueDeploy the app — and that’s it! 🎉
You’ve successfully migrated from GoodJob to Solid Queue.
But… wait a minute… what is that R14?
My app is deployed on Heroku, running on a Basic Dyno with 512 MB of RAM — yes, it’s 2025 and I’m still living on 512 MB 😭.
I’m paying $12/month for those 512 MB and a single database. The Kamal deploy is already cooking, but I wanted to see if I could make this setup work for now.
I tried reducing everything as much as possible in
config/queue.yml, but even after those changes, Solid Queue still consumed a lot of memory:default: &default
dispatchers:
- polling_interval: 60
batch_size: 50
workers:
- queues: "*"
threads: 1
processes: 1
polling_interval: 60Why does Solid Queue use more memory?
Sources: #679 and #644
From my understanding, Solid Queue runs a supervisor process, which forks worker and dispatcher processes.
From my understanding, Solid Queue runs a supervisor process, which forks worker and dispatcher processes.
These processes poll the database for ready jobs, then execute them — and each forked process adds memory overhead.
puma process ├── solid_queue supervisor │ ├── dispatcher │ ├── worker 1 └── (Rails threads)
So no matter what I change, memory usage won’t go below ~512 MB.
That makes Solid Queue not suitable for memory-constrained environments (like small Heroku dynos).
There’s hope!
There’s hope!
While I’m writing this, there’s an open initiative to bring back async mode, which would allow Solid Queue to run with a single process.
That would make it viable again for lightweight deployments.
At this point, I decided to roll back to GoodJob.
After tweaking the number of Puma threads (default is 3 — introduced in Rails 7.2), here’s the result:
Why such a big difference?
TIL: I should’ve checked that before trying to migrate 😅 — I had set it up over two years ago and completely forgot about it.
Conclusion
As of November 2025, Solid Queue is not ready for memory-constrained environments.
In practice, it’s likely not suitable for setups under 1 GB of RAM, since each forked process loads the full Rails app (typically 150–250 MB baseline).
In practice, it’s likely not suitable for setups under 1 GB of RAM, since each forked process loads the full Rails app (typically 150–250 MB baseline).
Once it lands, Solid Queue could become a strong option even for smaller deployments.
🎉 Happy Migration
🎉 Happy Migration