Database

CarrierWave to Shrine Migration in Legacy Rails

BLUF (Bottom Line Up Front): Legacy CarrierWave implementations load entire files into memory during processing, causing severe memory spikes in background workers. The architectural fix is migrating to Shrine. Shrine’s modular architecture, powered by Shrine plugins, streams files directly and supports backgrounding natively, drastically reducing RAM usage.

CarrierWave vs Shrine: file uploader architecture
AspectCarrierWaveShrine
ArchitectureMonolithic uploader classesPlugin-based, opt-in features
Background processingcarrierwave_backgrounder gemBuilt-in backgrounding plugin
Direct uploadscarrierwave-aws + manual setupshrine/plugins/presign_endpoint
Metadata extractionHard-coded in uploaderFirst-class via metadata plugins
ValidationBuilt-in but rigidComposable via validation plugin
Test fixturesFile upload onlyMocked storage + in-memory storage
Rails couplingTightly coupled to RailsRails-agnostic core

Phase 1: The Memory Problem

In older Rails applications, CarrierWave processes image thumbnails synchronously or requires brittle third-party gems for backgrounding.

Synthetic Engineering Context: CarrierWave Bloat

When a user uploads a 20MB image, CarrierWave reads it into RAM. If 10 users upload simultaneously, your worker process memory spikes, leading to an OOM (Out of Memory) crash.

# Legacy CarrierWave Uploader
class ImageUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
  
  # This block loads the file into memory synchronously
  version :thumb do
    process resize_to_fill: [200, 200]
  end
end

Phase 2: The Shrine Solution

Shrine treats file uploads as streams and delegates features to isolated Shrine plugins. Direct uploads to S3 are handled client-side, and processing is offloaded cleanly.

# config/initializers/shrine.rb
require "shrine"
require "shrine/storage/s3"

Shrine.storages = {
  cache: Shrine::Storage::S3.new(prefix: "cache", **s3_options),
  store: Shrine::Storage::S3.new(prefix: "store", **s3_options),
}

# Enable crucial Shrine plugins
Shrine.plugin :activerecord           # ActiveRecord integration
Shrine.plugin :cached_attachment_data # Retain cached file across form redisplays
Shrine.plugin :restore_cached_data    # Extract metadata for cached files
Shrine.plugin :backgrounding          # Asynchronous processing

By enabling the backgrounding plugin, Shrine promotes the cached file to permanent storage and generates thumbnails via Sidekiq, keeping the web process completely free of heavy I/O operations.

Need Help Stabilizing Your Legacy App? Replacing a core upload engine like CarrierWave requires careful data mapping and infrastructure changes. Our team at USEO can execute a CarrierWave to Shrine migration, optimizing your workers and eliminating OOM errors.

Contact us for a Technical Debt Audit