Common Shakapacker Upgrade Guides
This document provides step-by-step instructions for the most common upgrade scenarios in Shakapacker projects.
📖 For configuration options, see the Configuration Guide
Table of Contents
- Upgrading Shakapacker
- Adopting Supplemental Packages (10.1+)
- Automating Updates with Dependabot
- Migrating Package Managers
- Migrating from Babel to SWC
- Migrating from Webpack to Rspack
Upgrading Shakapacker
⚠️ Important: Shakapacker is both a Ruby gem AND an npm package. You must update BOTH when upgrading.
Shakapacker consists of two components that must be updated together:
- Ruby gem - provides Rails integration and view helpers
- npm package - provides webpack/rspack configuration and build tools
Upgrade Steps
1. Update Gemfile
gem "shakapacker", "10.0.0" # or the version you want to upgrade to
Pre-release versions: Ruby gems use dot notation (e.g., "10.0.0.beta.1")
2. Update package.json
{
"dependencies": {
"shakapacker": "10.0.0"
}
}
Pre-release versions: npm uses hyphen notation (e.g., "10.0.0-beta.1")
3. Run bundler and package manager
bundle update shakapacker
yarn install # or npm install, pnpm install, bun install
4. Test your build
bin/shakapacker
bin/shakapacker-dev-server
Why Both Must Be Updated
- Mismatched versions can cause build failures - The Ruby gem expects specific configuration formats from the npm package
- Feature compatibility - New features in the gem require corresponding npm package updates
- Bug fixes - Fixes often span both Ruby and JavaScript code
Version Format Differences
Note that pre-release versions use different formats:
| Component | Stable Version | Pre-release Version |
|---|---|---|
| Gemfile | "10.0.0" | "10.0.0.beta.1" |
| package.json | "10.0.0" | "10.0.0-beta.1" |
Finding the Latest Version
- Ruby gem: Check RubyGems.org
- npm package: Check npmjs.com
- Releases: See GitHub Releases
Major Version Upgrades
For major version upgrades, always consult the version-specific upgrade guides for breaking changes and new features:
- v10.0.0 Release Notes - Upgrading from v9 to v10 (includes webpack and dev-server minimum version changes)
- V9 Upgrade Guide - Upgrading from v8 to v9 (includes CSS Modules changes, SWC defaults, and more)
- V8 Upgrade Guide - Upgrading from v7 to v8
- V7 Upgrade Guide - Upgrading from v6 to v7
- V6 Upgrade Guide - Upgrading from v5 to v6
💡 Note: Major version upgrades may include breaking changes. The steps above cover the basic gem/package updates that apply to all versions, but you should always review the version-specific guide for additional migration steps.
Adopting Supplemental Packages (10.1+)
Shakapacker 10.1 introduces two optional npm packages — shakapacker-webpack and shakapacker-rspack — that bundle the managed-build stack as direct dependencies. Adopting one of them lets you replace four explicit devDependencies (shakapacker + bundler + CLI + manifest plugin) with a single package that lockstep-pins to the exact versions Shakapacker is tested against.
This is opt-in. Apps that don't change anything keep working on 10.1 exactly as they did on 10.0.
Rspack apps can replace shakapacker + @rspack/core + @rspack/cli + rspack-manifest-plugin with a single shakapacker-rspack dev dependency.
Webpack apps can replace shakapacker + webpack + webpack-cli + webpack-assets-manifest with a single shakapacker-webpack dev dependency. One caveat: shakapacker-webpack pins webpack-assets-manifest to ~6.5.1, so apps still on webpack-assets-manifest@5.x need to upgrade to v6 when adopting it.
Custom-build apps (apps that ship their own webpack/rspack/Vite setup and only use Shakapacker to read manifest.json) should not install a supplemental package — continue using bare shakapacker.
See the v10.1 supplemental packages migration guide for before/after package.json snippets, the webpack-assets-manifest v5→v6 upgrade notes, and the v11 roadmap context. The per-package install references live at packages/shakapacker-webpack/README.md and packages/shakapacker-rspack/README.md.
Automating Updates with Dependabot
Because Shakapacker ships as both a Ruby gem and an npm package, both sides must be bumped together. Dependabot's multi-ecosystem groups can open a single PR that updates both ecosystems at once.
See Dependabot configuration for Shakapacker for an example
.github/dependabot.yml that keeps the gem and npm package in sync.
Migrating Package Managers
Yarn to npm
Migrating from Yarn to npm is straightforward as both use similar package management concepts.
1. Remove Yarn lock file
rm yarn.lock
2. Install dependencies with npm
npm install
This will create a new package-lock.json file.
3. Update scripts (if necessary)
Review your package.json scripts and any deployment scripts that may reference yarn commands. Replace them with npm equivalents:
{
"scripts": {
"build": "shakapacker",
"dev": "shakapacker-dev-server"
}
}
4. Update CI/CD pipelines
If you have CI/CD pipelines, update them to use npm install instead of yarn install.
5. Test your build
npm run build
Common npm equivalents
| Yarn Command | npm Equivalent |
|---|---|
yarn | npm install |
yarn add <package> | npm install <package> |
yarn add --dev <package> | npm install --save-dev <package> |
yarn remove <package> | npm uninstall <package> |
yarn run <script> | npm run <script> |
npm to Yarn
Converting from npm to Yarn is equally straightforward.
1. Remove npm lock file
rm package-lock.json
2. Install Yarn (if not already installed)
Use Corepack (recommended for modern Node.js):
corepack enable
corepack prepare yarn@stable --activate
Alternative - install globally via npm:
npm install -g yarn
3. Install dependencies with Yarn
yarn install
This will create a new yarn.lock file.
4. Update scripts
Yarn can run scripts directly without the run command:
# Both work with Yarn
yarn build
yarn run build
5. Test your build
yarn build
Migrating to pnpm
pnpm is a fast, disk space-efficient package manager that's gaining popularity.
1. Install pnpm
Use Corepack (recommended):
corepack enable
corepack prepare pnpm@latest --activate
Alternative - install globally via npm:
npm install -g pnpm
2. Remove existing lock files
rm yarn.lock package-lock.json
3. Install dependencies with pnpm
pnpm install
This creates a pnpm-lock.yaml file.
4. Update scripts (if necessary)
pnpm uses the same script syntax as npm/Yarn:
pnpm run build
pnpm dev
5. Configure pnpm workspace (optional)
If you have a monorepo setup, create a pnpm-workspace.yaml:
packages:
- "packages/*"
6. Test your build
pnpm run build
pnpm benefits
- Faster installs: Uses pnpm's content-addressable store and hard links to speed up repeat installs
- Disk space efficient: Uses hard links to save disk space
- Strict: Better at catching dependency issues
Migrating from Babel to SWC
SWC is a high-performance Rust-based JavaScript/TypeScript compiler. SWC reports being 20x faster than Babel on a single thread and 70x faster on four cores in its own transpiler benchmark; the practical speedup on a full Shakapacker build is usually smaller but still substantial. For complete details, see JavaScript Transpiler Configuration.
Quick Migration Steps
1. Install SWC dependencies
# Using Yarn
yarn add --dev @swc/core swc-loader
# Using npm
npm install --save-dev @swc/core swc-loader
# Using pnpm
pnpm add --save-dev @swc/core swc-loader
2. Update shakapacker.yml
# config/shakapacker.yml
default: &default
javascript_transpiler: swc
3. Run the migration rake task (recommended)
bundle exec rake shakapacker:migrate_to_swc
This will automatically create a config/swc.config.js with sensible defaults, including Stimulus compatibility if needed.
4. Create SWC configuration (if not using rake task)
If you're configuring manually, create config/swc.config.js:
// config/swc.config.js
// This file is merged with Shakapacker's default SWC configuration
// See: https://swc.rs/docs/configuration/compilation
module.exports = {
options: {
jsc: {
// CRITICAL for Stimulus compatibility: Prevents SWC from mangling class names
keepClassNames: true,
transform: {
react: {
runtime: "automatic"
}
}
}
}
}
Note: The options wrapper is required for proper merging with Shakapacker's defaults. Using .swcrc instead will completely override Shakapacker's settings and may cause build failures.
5. Update React refresh plugin (if using React)
# For webpack
yarn add --dev @pmmmwh/react-refresh-webpack-plugin
# For rspack
yarn add --dev @rspack/plugin-react-refresh
6. Test your build
bin/shakapacker
7. Run your test suite
# Ensure everything works as expected
bundle exec rspec
Performance Expectations
SWC's own benchmark reports being 20x faster than Babel single-threaded and 70x faster on four cores for pure transpilation. A real Shakapacker build also runs CSS processing, minification, source map generation, and your plugin chain, so the end-to-end speedup is typically smaller than the transpiler number in isolation — but the transpiler is usually the dominant cost on Babel-heavy projects, so the move is almost always a large win.
Exact gains depend on project size, configuration, source maps, cache state, hardware, and whether you measure only transpilation or the full Shakapacker build. See Measuring Your App for how to confirm the gain on your codebase.
Common Issues
Issue: Decorators not working
Add decorator support to config/swc.config.js:
module.exports = {
options: {
jsc: {
parser: {
decorators: true,
decoratorsBeforeExport: true
}
}
}
}
Issue: Stimulus controllers not working
Ensure keepClassNames: true is set in config/swc.config.js.
Rollback
If you need to revert:
# config/shakapacker.yml
default: &default
javascript_transpiler: babel
Then rebuild:
bundle exec rake shakapacker:clobber
bundle exec rake shakapacker:compile
Migrating from Webpack to Rspack
Rspack is a high-performance bundler written in Rust with excellent webpack compatibility. Rspack's published benchmark on a 5,000-component React app reports roughly 8x faster production builds, 10–15x faster development startup, and 17x faster HMR vs webpack (rspack.rs, benchmark sources). For complete details, see Rspack Migration Guide.
Quick Migration Steps
1. Use the switch bundler rake task (recommended)
Shakapacker provides a convenient rake task to automate the migration:
# Switch to rspack with automatic dependency management (note the -- separator)
bin/rake shakapacker:switch_bundler rspack -- --install-deps
# Fast switching without uninstalling webpack (keeps both)
bin/rake shakapacker:switch_bundler rspack -- --install-deps --no-uninstall
⚠️ Important: This task must be run with
bin/rake, notbin/rails.
The task will:
- Update
config/shakapacker.ymlto use rspack - Install rspack dependencies (with
--install-deps) - Optionally uninstall webpack dependencies (default) or keep both (with
--no-uninstall) - Update
javascript_transpilertoswc(recommended for rspack) - Preserve your config file comments and structure
Custom dependencies: You can customize which dependencies are installed:
bin/rake shakapacker:switch_bundler -- --init-config
2. Manual installation (alternative)
If you prefer manual control:
# Install Rspack dependencies
# Using Yarn
yarn add --dev @rspack/core @rspack/cli
# Using npm
npm install --save-dev @rspack/core @rspack/cli
# Using pnpm
pnpm add --save-dev @rspack/core @rspack/cli
# Remove webpack dependencies (optional)
yarn remove webpack webpack-cli webpack-dev-server
# Or: npm uninstall webpack webpack-cli webpack-dev-server
# Or: pnpm remove webpack webpack-cli webpack-dev-server
Then update config/shakapacker.yml:
default: &default
assets_bundler: rspack
javascript_transpiler: swc # Rspack defaults to SWC for best performance
3. Create Rspack configuration
Create config/rspack/rspack.config.js based on your webpack config. Start with a minimal configuration:
// config/rspack/rspack.config.js
const { rspack } = require("@rspack/core")
const { merge } = require("webpack-merge")
const baseConfig = require("../shakapacker")
module.exports = merge(baseConfig, {
module: {
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
loader: "builtin:swc-loader",
options: {
jsc: {
parser: {
syntax: "ecmascript",
jsx: true
},
transform: {
react: {
runtime: "automatic"
}
}
}
}
}
]
}
})
4. Update TypeScript configuration
Add isolatedModules: true to your tsconfig.json:
{
"compilerOptions": {
"isolatedModules": true
}
}
5. Replace incompatible plugins
Some webpack plugins need Rspack equivalents:
| Webpack Plugin | Rspack Alternative |
|---|---|
mini-css-extract-plugin | rspack.CssExtractRspackPlugin |
copy-webpack-plugin | rspack.CopyRspackPlugin |
terser-webpack-plugin | rspack.SwcJsMinimizerRspackPlugin |
fork-ts-checker-webpack-plugin | ts-checker-rspack-plugin |
@pmmmwh/react-refresh-webpack-plugin | @rspack/plugin-react-refresh |
Example plugin update:
// Before (webpack)
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
plugins: [new MiniCssExtractPlugin()]
// After (rspack)
const { rspack } = require("@rspack/core")
plugins: [new rspack.CssExtractRspackPlugin()]
6. Update asset handling
Replace file loaders with asset modules:
// Before (webpack with file-loader)
{
test: /\.(png|jpg|gif)$/,
use: ['file-loader']
}
// After (rspack with asset modules)
{
test: /\.(png|jpg|gif)$/,
type: 'asset/resource'
}
7. Install React refresh plugin (if using React)
yarn add --dev @rspack/plugin-react-refresh
Update your config:
const { ReactRefreshRspackPlugin } = require("@rspack/plugin-react-refresh")
const { rspack } = require("@rspack/core")
module.exports = {
plugins: [
new ReactRefreshRspackPlugin(),
new rspack.HotModuleReplacementPlugin()
]
}
8. Test your build
# Development build
bin/shakapacker
# Production build
bin/shakapacker --mode production
9. Update development workflow
Rspack's dev server works the same way:
bin/shakapacker-dev-server
Migration Checklist
- Install Rspack dependencies
- Update
config/shakapacker.yml - Create
config/rspack/rspack.config.js - Replace incompatible plugins
- Update TypeScript config (add
isolatedModules: true) - Convert file loaders to asset modules
- Test development build
- Test production build
- Run test suite
- Update CI/CD pipelines
- Deploy to staging
- Monitor performance improvements
Performance Benefits
Rspack's own published benchmark on a 5,000-component React app reports:
| Workload | Webpack 5 | Rspack | Approx. speedup |
|---|---|---|---|
| Cold development start | ~8.2s | ~0.7s | ~10x |
| Cold production build | ~9.5s | ~1.6s | ~6x |
| HMR update | ~2.8s | ~160ms | ~17x |
Source: rspack.rs and rstackjs/build-tools-performance (react-5k case).
Real Shakapacker apps will land somewhere in this range depending on project size, configuration, source maps, cache state, and hardware. Measure your real build and development workflows to confirm the gain on your app — see Measuring Your App.
Common Issues
Issue: LimitChunkCountPlugin Error
Error: Cannot read properties of undefined (reading 'tap')
Solution: Remove webpack.optimize.LimitChunkCountPlugin and use splitChunks configuration instead.
Issue: CSS not extracting
Solution: Use rspack.CssExtractRspackPlugin instead of mini-css-extract-plugin.
Issue: TypeScript errors
Solution: Ensure isolatedModules: true is set in tsconfig.json.
Rollback
If you need to revert to webpack:
# config/shakapacker.yml
default: &default
assets_bundler: webpack
javascript_transpiler: babel # or swc
Then rebuild:
bundle exec rake shakapacker:clobber
bundle exec rake shakapacker:compile
Combined Migration Path
For maximum performance improvements, you can combine multiple migrations:
Recommended: Webpack + Babel → Rspack + SWC
This combination provides the largest end-to-end build performance improvement available in Shakapacker: SWC handles transpilation in Rust (upstream reports up to 20x/70x vs Babel) and Rspack handles the rest of the bundler pipeline in Rust (upstream reports roughly 8–17x vs webpack on its own benchmark). Apply them in order so you can attribute any regression to the right layer:
-
First, migrate to SWC (while still on webpack)
- Follow Migrating from Babel to SWC
- Test thoroughly
- This is a smaller change to validate first
-
Then, migrate to Rspack
- Follow Migrating from Webpack to Rspack
- Rspack will use your existing SWC configuration
- Test thoroughly
Alternative: Webpack + Babel → Rspack + SWC (all at once)
If you're confident, you can do both migrations simultaneously:
# config/shakapacker.yml
default: &default
assets_bundler: rspack
javascript_transpiler: swc
Follow both migration guides, installing all required dependencies at once.