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
Killedorsignal 9without Ruby exception details dmesgrevealsOut 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.Increase Node.js memory limit:
- 2.```bash
- 3.# Set before running precompile
- 4.export NODE_OPTIONS="--max-old-space-size=4096"
- 5.bundle exec rake assets:precompile
- 6.
` - 7.Add swap space on the deployment server:
- 8.```bash
- 9.# Create 2GB swap file
- 10.sudo fallocate -l 2G /swapfile
- 11.sudo chmod 600 /swapfile
- 12.sudo mkswap /swapfile
- 13.sudo swapon /swapfile
# Make permanent echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
# Verify free -h ```
- 1.Configure Sprockets to use less memory:
- 2.```ruby
- 3.# config/environments/production.rb
- 4.config.assets.compile = false # Disable runtime compilation
- 5.config.assets.digest = true
- 6.config.assets.css_compressor = nil # Disable CSS compressor if memory constrained
- 7.
` - 8.Use esbuild or importmap instead of Sprockets for JS:
- 9.```bash
- 10.# Switch to esbuild (much lower memory usage)
- 11../bin/bundle add esbuild-rails
- 12../bin/rails javascript:install:esbuild
# Or use importmap for zero-build JS ./bin/bundle add importmap-rails ./bin/rails importmap:install ```
- 1.Precompile assets locally and upload:
- 2.```bash
- 3.# Precompile locally where memory is plentiful
- 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_OPTIONSin deployment scripts and Procfiles - Monitor memory usage during deployment with
toporhtop - Use
bundle exec rake assets:precompile:allonly when needed