Boxwerk is a tool for creating modular Ruby and Rails applications. It enables you to organize code into packages of Ruby files with clear boundaries and explicit dependencies. Boxwerk is heavily inspired by Packwerk but provides more robust enforcement at runtime using Ruby::Box, ensuring that only public constants from direct dependencies are accessible. Violations raise NameError, turning architectural rules into runtime guarantees.
As your application grows, Boxwerk helps prevent accidental coupling, enforces modularity, and makes it easier to understand and modify code without breaking other parts of the system.
Usage Guide Β· API Documentation Β· Changelog
- Boxwerk reads standard Packwerk
package.ymlfiles, supporting both dependency and privacy enforcement. Packwerk itself is not required. - Packages in a Boxwerk application share a set of global gems but may also define package-local ones. Multiple packages can depend on different versions of the same gem.
Ruby::Boxprovides monkey patch isolation between packages.- Boxwerk uses Zeitwerk to automatically load constants in packages with conventional file structure although manual loading is also supported.
- Enforce boundaries at runtime.
Ruby::Boxturns architectural rules into runtime guarantees. Undeclared dependencies and privacy violations raiseNameError. - Enable gradual modularization. Add
package.ymlfiles around existing code and declare dependencies incrementally. - Feel Ruby-native. Integrates with Bundler,
gems.rb/Gemfile, and standard Ruby tools.boxwerk exec rake testfeels like any other Ruby command.
Ruby::Box (Ruby 4.0+) provides in-process isolation of classes, modules, and constants. Each box has its own top-level Object, isolated $LOAD_PATH and $LOADED_FEATURES, and independent monkey patches. Boxwerk creates one box per package and wires cross-package constant resolution through const_missing.
Set RUBY_BOX=1 before starting Ruby. See the official documentation for details. See ARCHITECTURE.md for how Boxwerk uses Ruby::Box internally.
Create packages with package.yml files:
my_app/
βββ package.yml
βββ main.rb
βββ packs/
βββ foo/
β βββ package.yml
β βββ lib/foo.rb
βββ bar/
βββ package.yml
βββ lib/bar.rb
# package.yml (root)
enforce_dependencies: true
dependencies:
- packs/foo
- packs/barInstall and run:
gem install boxwerk
RUBY_BOX=1 boxwerk run main.rbNo Bundler or Gemfile required for basic usage. To use global or per-package gems, see USAGE.md.
boxwerk run <script.rb> Run a Ruby script in a package box
boxwerk exec <command> [args...] Execute a command in the boxed environment
boxwerk console Interactive console in a package box
boxwerk info Show package structure and dependencies
boxwerk install Install gems for all packages
Options: --package <package>, --all, --global. See USAGE.md for details.
Ruby::Boxis experimental in Ruby 4.0- No constant reloading (restart required for code changes)
- IRB autocomplete disabled in console
See TODO.md for plans to address these and other planned features.
examples/minimal/β Three packages, dependency enforcement, no gemsexamples/complex/β Namespaced constants, privacy, per-package gems, testsexamples/rails/β Usage with Rails
bundle install # Install dependencies
RUBY_BOX=1 bundle exec rake # Run all tests (unit, e2e, examples)
bundle exec rake format # Format codeAvailable as open source under the MIT License.