Hanami Slices
A slice is a self-contained sub-application within a Hanami project — its own actions, views, and container, but sharing the same process and deploy unit as the rest of the app. This is Hanami’s answer to “modular monolith”: bounded contexts without splitting into separate services.
Why split into slices
- A large domain gets hard to navigate as one flat
app/tree — an admin area, a public API, and a customer-facing app can each become a slice instead of all living under one namespace. - Each slice gets its own container, so dependencies are scoped: the admin slice doesn’t accidentally reach into public-facing view helpers, and vice versa.
- Slices can be tested in isolation — booting just the slice under test rather than the whole app speeds up the suite as the app grows.
Directory structure
slices/
admin/
actions/
views/
templates/
config/
routes.rb # optional, slice-specific routes
slice.rb # optional, slice-specific config/imports
api/
actions/
...
app/ # the main app, itself effectively the default "slice"
Running hanami generate slice admin scaffolds the directory and registers it — no manual wiring required for the common case.
Routing into a slice
# config/routes.rb (main app)
module MyApp
class Routes < Hanami::Routes
slice :admin, at: "/admin" do
root { "Admin dashboard" }
resources :users
end
end
end
Everything registered inside the slice :admin do ... end block resolves against the admin slice’s own container, not the main app’s.
Cross-slice dependencies
Slices are isolated by default — a slice can’t see another slice’s components unless it’s explicitly imported:
# slices/admin/config/slice.rb
module Admin
class Slice < Hanami::Slice
import from: :main, as: :main
end
end
# slices/admin/actions/users/index.rb
include Deps["main.repositories.user_repo"]
This keeps the dependency graph explicit and visible in one place per slice, rather than discoverable only by reading action bodies.
When not to bother
For a small app with one clear domain, slices are overhead for no benefit — the plain app/ directory is a slice already (the implicit “main” one), and most apps never need to split further. Reach for an explicit slice when a sub-area’s actions/views/dependencies genuinely don’t overlap with the rest — an admin panel and a public marketing site sharing one deploy are the canonical case, not “this controller folder feels big.”