Recommended Project Structure
React on Rails supports two main organizational approaches for your React components.
Modern Auto-Bundling Structure (Recommended)
The current React on Rails generator creates a component-based structure optimized for automatic bundle generation:
app/javascript/
├── src/
│ ├── HelloWorld/
│ │ ├── HelloWorld.module.css
│ │ └── ror_components/ # Auto-discovered by React on Rails
│ │ ├── HelloWorld.jsx # Client & server rendering
│ │ └── HelloWorld.server.js # Optional: server-only code
│ └── AnotherComponent/
│ └── ror_components/
│ ├── AnotherComponent.client.jsx # Client-only rendering
│ └── AnotherComponent.server.jsx # Server-only rendering
└── packs/
├── generated/ # Auto-generated entry points (gitignored)
│ ├── HelloWorld.js
│ └── AnotherComponent.js
└── server-bundle.js # Server rendering entry pointKey features:
- Components in
ror_components/directories are automatically discovered and registered - Each component gets its own webpack bundle for optimal code splitting
- No manual
ReactOnRails.register()calls needed - Supports separate
.client.jsxand.server.jsxfiles for different rendering logic
For details, see Auto-Bundling Guide and Generator Details.
Traditional Manual Structure (Legacy)
For projects requiring explicit control over webpack entry points:
app/javascript/
├── bundles/
│ └── HelloWorld/
│ ├── components/
│ │ └── HelloWorld.jsx
│ └── startup/
│ └── registration.js # Manual ReactOnRails.register()
└── packs/
└── hello-world-bundle.js # Webpack entry pointThis approach requires manual component registration and webpack configuration but offers complete control over bundling strategy.
Choosing Your Structure
Use modern auto-bundling if:
- Starting a new project
- Want automatic code splitting per component
- Prefer convention over configuration
- Want to minimize boilerplate
Use traditional manual structure if:
- Have complex custom webpack requirements
- Need fine-grained control over bundle composition
- Migrating from older React on Rails versions
For most projects, we recommend the modern auto-bundling approach.
Steps to convert from the generator defaults to use a /client directory for source code
- Move the directory:
mv app/javascript client- Edit your
/config/shakapacker.ymlfile. Change thedefault/source_path:
source_path: clientStyling Your Components
React on Rails supports multiple approaches for styling your components. The modern recommended approach uses CSS Modules with co-located stylesheets.
Modern Approach: CSS Modules (Recommended)
The generator creates components with CSS Module support out of the box:
app/javascript/src/HelloWorld/
├── ror_components/
│ ├── HelloWorld.client.jsx
│ └── HelloWorld.module.css # Co-located with componentExample usage:
import React from 'react';
import * as style from './HelloWorld.module.css';
const HelloWorld = () => <label className={style.bright}>Hello World</label>;Benefits:
- Scoped styles: Class names are automatically scoped to prevent conflicts
- Co-location: Styles live next to their components for better organization
- Type safety: Works seamlessly with TypeScript
- Hot reloading: Style changes reload instantly without page refresh
- Zero configuration: Works out of the box with the generator
Alternative: Rails Asset Pipeline
You can continue using Rails' traditional asset pipeline with sass-rails or similar gems:
<%# app/views/layouts/application.html.erb %>
<%= stylesheet_link_tag 'application', media: 'all' %>Use this approach when:
- You have existing Rails stylesheets you want to keep
- You prefer keeping styles completely separate from JavaScript
- You don't need component-scoped styling
Advanced: Global Styles with Webpack
For global styles (fonts, resets, variables), you can create additional webpack entry points:
app/javascript/
├── packs/
│ ├── application.css # Global styles
│ └── server-bundle.js
└── src/
└── HelloWorld/
└── ror_components/
├── HelloWorld.jsx
└── HelloWorld.module.cssImport global styles in your layout:
<%= stylesheet_pack_tag 'application' %>