Sidekiq is the de facto background job processor for Ruby on Rails. It's fast, memory-efficient (threaded, not process-forked), and backed by Redis. If your Rails app sends emails, processes images, or calls external APIs, those belong in Sidekiq jobs, not in the request cycle. Here's how to deploy it alongside Rails in production.
Two processes, one app
A Rails app with Sidekiq runs as two deployments from the same codebase:
| Process | Command | Public? |
|---|---|---|
| Web | rails server / Puma | yes |
| Worker | bundle exec sidekiq | no |
Both connect to the same PostgreSQL (your app data) and the same Redis (the job queue). The web process enqueues jobs; the Sidekiq process executes them.
Wiring up Redis
Sidekiq reads its Redis URL from configuration. Use an initializer so both client and server point at the same instance:
# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
config.redis = { url: ENV.fetch('REDIS_URL') }
end
Sidekiq.configure_client do |config|
config.redis = { url: ENV.fetch('REDIS_URL') }
endOn PandaStack, attach a managed Redis and inject REDIS_URL into both the web and worker services. Your managed PostgreSQL provides DATABASE_URL to both as usual.
Active Job vs the Sidekiq API
Rails' Active Job abstraction can use Sidekiq as its backend (config.active_job.queue_adapter = :sidekiq). That's portable and fine. For features like batches, rate limiting, and unique jobs you'll reach for Sidekiq's native API directly. Either way the deployment is identical.
class HardWorker
include Sidekiq::Job
sidekiq_options queue: :default, retry: 5
def perform(user_id)
# ...
end
endThe concurrency / connection-pool trap
Sidekiq's default concurrency is 10 threads. Each thread that touches the database checks out a connection from Rails' connection pool. If your Sidekiq concurrency exceeds the pool size, threads block waiting for connections — a subtle source of latency. The rule: RAILS_MAX_THREADS (pool size) >= Sidekiq concurrency.
bundle exec sidekiq -c 10
# ensure database.yml pool >= 10, via RAILS_MAX_THREADS=10Also mind your managed database's total connection limit: web Puma threads + Sidekiq threads + replicas all draw from it. On a small tier this adds up fast — count your connections before scaling replicas.
Queues and priority
Name queues by urgency and tell Sidekiq their order:
bundle exec sidekiq -q critical -q default -q lowThis is strict priority — Sidekiq drains critical before touching default. For weighted fairness, use the -q queue,weight form. Put user-facing work (password resets) in a high-priority queue and bulk work (analytics rollups) in a low one so a flood of low-priority jobs never delays the important ones.
Scheduled and recurring jobs
Sidekiq supports scheduled jobs (perform_in, perform_at) natively. For recurring cron-style jobs, the open-source ecosystem uses gems like sidekiq-cron, and Sidekiq Enterprise has periodic jobs built in. Alternatively, use your platform's native cronjobs to invoke a Rake task on a schedule, which keeps recurring logic out of a long-running scheduler process. PandaStack cronjobs can run bundle exec rake some:task on a cron expression for exactly this.
Monitoring
Mount the Sidekiq Web UI behind authentication to watch queues, retries, and the dead set:
require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq' # protect with auth!Never expose /sidekiq unauthenticated — it can enqueue and delete jobs.
Go-live checklist
- Web + Sidekiq as separate services, same image
- Managed Redis;
REDIS_URLin both - DB pool size >= Sidekiq concurrency
- Total connections under the database limit
- Priority queues defined
- Web UI behind auth
- Recurring jobs via gem or platform cronjobs
References
- [Sidekiq wiki: Deployment](https://github.com/sidekiq/sidekiq/wiki/Deployment)
- [Sidekiq + Redis configuration](https://github.com/sidekiq/sidekiq/wiki/Using-Redis)
- [Sidekiq advanced options (concurrency, queues)](https://github.com/sidekiq/sidekiq/wiki/Advanced-Options)
- [Active Job basics](https://guides.rubyonrails.org/active_job_basics.html)
Sidekiq pairs naturally with PandaStack: deploy Rails and the worker as two services from one repo, attach managed Redis and PostgreSQL, and lean on native cronjobs for recurring tasks. Get started on the free tier at [dashboard.pandastack.io](https://dashboard.pandastack.io).