Simplify Nested Routes in Rails with shallow: true

When dealing with nested resources in Ruby on Rails, long and deeply nested URLs can quickly become a problem. That’s where the shallow option comes in.

Setting shallow: true is a simple yet powerful way to keep your routes clean, maintainable, and RESTful — without giving up the structure that nesting provides.

What Does shallow: true Do?

By default, Rails fully nests all routes for a resource under its parent(s). But with shallow: true, Rails only nests the routes that truly need the parent context — typically index and create.

Let’s look at an example:

1
2
3
resources :albums do
  resources :photos, shallow: true
end

This will generate routes like:

1
2
3
4
5
6
GET    /albums/:album_id/photos      # index
POST   /albums/:album_id/photos      # create
GET    /photos/:id                         # show
PATCH  /photos/:id                         # update
DELETE /photos/:id                         # destroy
GET    /photos/:id/edit                    # edit

So instead of requiring an album_id for every action on a photo, only the routes that really need it (like creating or listing photos within an album) are nested.

Why Use shallow: true?

Using shallow: true helps in several ways:

This approach keeps the benefits of nesting (clear relationships between models) without introducing the downsides of over-nesting.

When Not to Use Shallow Routes

If your child resource doesn’t make sense outside the context of its parent, or you want to enforce that context in every request strictly, shallow routing might not be the right choice.

For example, if Photo absolutely cannot be accessed without its associated Album, then requiring album_id in all routes (i.e., using shallow: false, or omitting shallow) may provide helpful guardrails.

Deep Nesting? Shallow Helps.

Deeply nested routes like:

1
/projects/:project_id/tasks/:task_id/comments/:comment_id

can quickly become a nightmare to manage. With shallow routing, you can still define these relationships, but only nest what’s necessary:

1
2
3
4
5
resources :projects do
  resources :tasks, shallow: true do
    resources :comments, shallow: true
  end
end

This reduces URL depth and simplifies controller code — without losing the structure of your models.

Use shallow: true when: