35+ Years Experience Netherlands Based ⚡ Fast Response Times Ruby on Rails Experts AI-Powered Development Fixed Pricing Available Senior Architects Dutch & English 35+ Years Experience Netherlands Based ⚡ Fast Response Times Ruby on Rails Experts AI-Powered Development Fixed Pricing Available Senior Architects Dutch & English
Rails 8 Solid Cache: Drop Redis and Memcached for Good

Rails 8 Solid Cache: Drop Redis and Memcached for Good

TTB Software
ruby-on-rails

Solid Cache stores your Rails cache in the database instead of Redis or Memcached. If you’re running Rails 8, you can cut an entire infrastructure dependency from your stack today.

Rails 8 ships with Solid Cache as the default cache store for new applications. It writes cache entries to a dedicated database table using ActiveRecord, which means your existing PostgreSQL or MySQL instance handles caching without a separate service. For most applications, this setup performs well enough that Redis becomes unnecessary overhead.

I’ve migrated three production Rails apps from Redis-backed caching to Solid Cache over the past six months. Here’s what worked, what surprised me, and the configuration details you need to get it running properly.

Why the Database Works for Caching

The knee-jerk reaction is “the database is too slow for caching.” That was true fifteen years ago. Modern SSDs changed the equation.

Solid Cache stores entries in a single table with indexed lookups. On a PostgreSQL 16 instance running on NVMe storage, I measured read latencies of 0.3-0.8ms for cached fragments — compared to 0.1-0.3ms for Redis over a local socket. That 0.5ms difference is invisible to users and irrelevant for 95% of web applications.

The real win is operational. You eliminate:

  • A Redis server to monitor, patch, and scale
  • Memory management headaches (Redis eviction policies, maxmemory configuration)
  • Connection pool tuning between Rails and Redis
  • A separate backup strategy for cached data
  • Network hops in containerized deployments

For applications already running PostgreSQL, Solid Cache means zero additional infrastructure.

Installation and Setup

If you’re on Rails 8.0+, Solid Cache is already in your Gemfile for new apps. For existing applications, add it:

# Gemfile
gem "solid_cache"

Run the installer:

bin/rails solid_cache:install

This generates a migration and a configuration file. Run the migration:

bin/rails db:migrate

The migration creates a solid_cache_entries table with columns for key, value, key_hash, byte_size, and timestamps. The key_hash column uses a bigint index for fast lookups — this is how Solid Cache avoids scanning text columns.

Configure the Cache Store

In config/environments/production.rb:

config.cache_store = :solid_cache_store

That’s it for basic setup. Solid Cache reads its configuration from config/solid_cache.yml:

default: &default
  store_options:
    max_age: <%= 60.days.to_i %>
    max_size: <%= 256.megabytes %>
    namespace: null

production:
  <<: *default
  store_options:
    max_age: <%= 30.days.to_i %>
    max_size: <%= 1.gigabyte %>

Using a Separate Database

For high-traffic applications, point Solid Cache at a dedicated database to isolate cache I/O from your application queries. In config/database.yml:

production:
  primary:
    <<: *default
    database: myapp_production
  cache:
    <<: *default
    database: myapp_cache_production
    migrations_paths: db/cache_migrate

Then in config/solid_cache.yml:

production:
  databases:
    - cache

This keeps cache writes from competing with your application’s read/write patterns. On one app processing 2,000 requests per minute, separating the cache database reduced p95 response times by 12% during cache-heavy operations.

Cache Expiration and Cleanup

Solid Cache handles expiration differently than Redis. Redis evicts keys based on memory pressure and TTL. Solid Cache uses a background thread that periodically deletes expired entries.

The cleanup runs automatically when you set max_age and max_size. Entries older than max_age get deleted first. If the total cache size still exceeds max_size, the oldest entries are removed until the size target is met.

You can tune the cleanup frequency:

production:
  store_options:
    max_age: <%= 30.days.to_i %>
    max_size: <%= 1.gigabyte %>
    expiry_batch_size: 100
    expiry_method: delete

The expiry_batch_size controls how many rows are deleted per cleanup cycle. Keep this reasonable — deleting 10,000 rows at once will lock the table and spike your database load. I’ve found 100-500 works well for most setups.

Production Performance Tuning

Connection Pool Sizing

If you’re using a separate cache database, size its connection pool independently:

production:
  cache:
    <<: *default
    database: myapp_cache_production
    pool: <%= ENV.fetch("CACHE_DB_POOL", 5) %>

Match the pool size to your Puma thread count. Each thread can hold one cache database connection during a request.

Write Coalescing

Solid Cache 1.0+ supports write coalescing — batching multiple cache writes into a single database transaction. This reduces write amplification significantly:

production:
  store_options:
    cluster:
      shards:
        - cache
    max_age: <%= 30.days.to_i %>
    max_size: <%= 1.gigabyte %>

In my benchmarks, write coalescing reduced cache-related database transactions by 40-60% under load.

Monitoring Cache Size

Keep tabs on your cache table size:

SELECT pg_size_pretty(pg_total_relation_size('solid_cache_entries'));
SELECT count(*) FROM solid_cache_entries;

Set up a recurring check. If the table grows past your max_size target, the cleanup process might be falling behind — increase expiry_batch_size or run manual cleanup:

SolidCache::Entry.clear_delete

Migrating from Redis

The migration path is straightforward because cache data is ephemeral by definition. You don’t need to transfer existing cached values.

  1. Deploy Solid Cache alongside your existing Redis cache
  2. Switch the cache store in production config
  3. Deploy — the cache starts cold and warms up organically
  4. Monitor for a few days
  5. Remove the Redis dependency

If you’re using Redis for background jobs with Solid Queue and WebSockets with Solid Cable, you can drop Redis entirely from your stack.

The cold cache period is the only concern. For fragment caching, pages load slightly slower for the first request after deploy. For API response caching, clients see cache misses temporarily. Neither is a real problem — your app handled these requests before caching existed.

What About Action Cable?

If you’re still using Redis for Action Cable, check out Solid Cable — Rails 8’s database-backed replacement for the Redis Action Cable adapter.

When Solid Cache Isn’t the Right Choice

Solid Cache isn’t universally better than Redis. Skip it if:

  • You cache more than 10GB of data. Database storage is cheaper than RAM, but very large cache tables slow down cleanup cycles and can impact vacuum performance in PostgreSQL.
  • You need sub-millisecond cache reads at scale. If your app serves 50,000+ requests per second and every microsecond counts, Redis in-memory reads are genuinely faster.
  • You’re already running Redis for other purposes. If Redis powers your Sidekiq queues, rate limiting, and session storage, adding caching to it costs nothing extra.
  • You use cache-specific Redis features. Sorted sets, pub/sub patterns, or Lua scripting in your caching layer can’t be replicated with Solid Cache.

For the vast majority of Rails applications — those handling under 5,000 requests per minute with cache sizes under a few gigabytes — Solid Cache performs identically to Redis from the user’s perspective while simplifying your infrastructure.

FAQ

Does Solid Cache work with PostgreSQL and MySQL?

Yes. Solid Cache uses ActiveRecord, so it works with any database ActiveRecord supports. PostgreSQL and MySQL are the most tested and recommended options. SQLite works for development but isn’t recommended for production caching due to write locking.

How much disk space does Solid Cache use compared to Redis memory?

Roughly 2-3x more per entry because of database row overhead and indexing. A 1GB Redis cache translates to approximately 2-3GB on disk. Since disk is dramatically cheaper than RAM, the cost difference still favors Solid Cache in most deployments.

Can I use Solid Cache with Rails 7?

Solid Cache requires Rails 7.1 or later. The gem works with Rails 7.1 and 7.2, but the seamless default integration and generator support are Rails 8 features. On Rails 7.x, you’ll need to configure the migration paths and database connections manually.

Will Solid Cache slow down my database?

It depends on your setup. If you use a separate database for caching, the impact on your primary database is zero. If you share the primary database, cache reads and writes compete with application queries. For low-to-medium traffic apps, this is negligible. For high-traffic apps, always use a dedicated cache database.

How do I monitor Solid Cache hit rates?

Rails built-in cache instrumentation works with Solid Cache. Subscribe to cache_read.active_support and cache_write.active_support events in your observability setup. You can calculate hit rates from cache_read events where the :hit payload is true versus false.

#rails-8 #caching #solid-cache #performance #production
T

About the Author

Roger Heykoop is a senior Ruby on Rails developer with 19+ years of Rails experience and 35+ years in software development. He specializes in Rails modernization, performance optimization, and AI-assisted development.

Get in Touch

Share this article

Need Expert Rails Development?

Let's discuss how we can help you build or modernize your Rails application with 19+ years of expertise

Schedule a Free Consultation