Introduction

During Rails deployment, the assets:precompile task can consume excessive memory and get killed by the OOM killer, especially on servers with limited RAM. This commonly happens when the JavaScript runtime (mini_racer, therubyracer, or Node.js) processes large bundles during Sprockets or Propshaft compilation. The deployment fails silently or with a vague "killed" message.

Symptoms

  • Deployment fails during bundle exec rake assets:precompile
  • Server logs show Killed or signal 9 without Ruby exception details
  • dmesg reveals Out of memory: Killed process (ruby) entries
  • Precompile works locally but fails on production server
  • Memory usage spikes to 100% during asset compilation

Check dmesg for OOM kills: ``bash sudo dmesg | grep -i "killed|oom|out of memory" # Example output: # [12345.678901] Out of memory: Killed process 5432 (ruby) total-vm:1048576kB, anon-rss:943744kB

Common Causes

  • Node.js default memory limit (4GB) exceeded during JS bundling
  • mini_racer libv8 embedded V8 engine requires significant memory
  • Large JavaScript bundles with many dependencies
  • Server with less than 2GB RAM running precompile
  • No swap space configured on deployment target
  • Source maps enabled in production build configuration

Step-by-Step Fix

  1. 1.Increase Node.js memory limit:
  2. 2.```bash
  3. 3.# Set before running precompile
  4. 4.export NODE_OPTIONS="--max-old-space-size=4096"
  5. 5.bundle exec rake assets:precompile
  6. 6.`
  7. 7.Add swap space on the deployment server:
  8. 8.```bash
  9. 9.# Create 2GB swap file
  10. 10.sudo fallocate -l 2G /swapfile
  11. 11.sudo chmod 600 /swapfile
  12. 12.sudo mkswap /swapfile
  13. 13.sudo swapon /swapfile

# Make permanent echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# Verify free -h ```

  1. 1.Configure Sprockets to use less memory:
  2. 2.```ruby
  3. 3.# config/environments/production.rb
  4. 4.config.assets.compile = false # Disable runtime compilation
  5. 5.config.assets.digest = true
  6. 6.config.assets.css_compressor = nil # Disable CSS compressor if memory constrained
  7. 7.`
  8. 8.Use esbuild or importmap instead of Sprockets for JS:
  9. 9.```bash
  10. 10.# Switch to esbuild (much lower memory usage)
  11. 11../bin/bundle add esbuild-rails
  12. 12../bin/rails javascript:install:esbuild

# Or use importmap for zero-build JS ./bin/bundle add importmap-rails ./bin/rails importmap:install ```

  1. 1.Precompile assets locally and upload:
  2. 2.```bash
  3. 3.# Precompile locally where memory is plentiful
  4. 4.RAILS_ENV=production bundle exec rake assets:precompile

# Upload to server via rsync rsync -avz public/assets/ deploy@server:/path/to/app/public/assets/ ```

Prevention

  • Use CI/CD pipeline with sufficient memory for asset compilation
  • Configure swap space on all deployment servers (minimum 2GB)
  • Consider moving to esbuild or importmap to eliminate heavy JS runtimes
  • Set NODE_OPTIONS in deployment scripts and Procfiles
  • Monitor memory usage during deployment with top or htop
  • Use bundle exec rake assets:precompile:all only when needed