Set up a new Inertia Rails project or add Inertia to an existing Rails application...
This skill helps you set up Inertia.js in a Ruby on Rails application with your choice of frontend framework.
For new projects, the fastest way to get started is cloning an official starter kit. These include authentication, shadcn/ui components, TypeScript, and optional SSR support out of the box.
git clone https://github.com/inertia-rails/react-starter-kit myapp
cd myapp
bin/setup
Includes:
git clone https://github.com/inertia-rails/vue-starter-kit myapp
cd myapp
bin/setup
git clone https://github.com/inertia-rails/svelte-starter-kit myapp
cd myapp
bin/setup
After cloning:
Rename the app:
# Update config/application.rb
module YourAppName
class Application < Rails::Application
Update database config:
# Edit config/database.yml with your settings
Remove example pages you don't need:
# Delete from app/frontend/pages/ and corresponding controllers
Add your own pages:
bin/rails generate controller Products index show
# Create app/frontend/pages/products/index.tsx
Customize the layout:
app/frontend/layouts/app-layout.tsx for main appapp/frontend/components/nav-main.tsx for navigationIf you prefer starting from scratch or adding Inertia to an existing Rails app:
# Create new Rails app (if needed)
rails new myapp --skip-javascript
# Add inertia_rails gem
bundle add inertia_rails
# Run the generator
bin/rails generate inertia:install
The generator will prompt you to select:
# Gemfile
gem 'inertia_rails'
bundle install
bundle add vite_rails
bundle exec vite install
Create or update app/views/layouts/application.html.erb:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csp_meta_tag %>
<%= inertia_ssr_head %>
<%= vite_client_tag %>
<%= vite_javascript_tag 'application' %>
</head>
<body>
<%= yield %>
</body>
</html>
For React:
npm install @inertiajs/react @inertiajs/vite react react-dom
For Vue 3:
npm install @inertiajs/vue3 @inertiajs/vite vue
For Svelte:
npm install @inertiajs/svelte @inertiajs/vite svelte
Create app/frontend/entrypoints/application.js:
React:
import { createInertiaApp } from '@inertiajs/react'
import { createRoot } from 'react-dom/client'
import { inertia } from '@inertiajs/vite'
createInertiaApp({
resolve: inertia.resolvePages('../pages'),
setup({ el, App, props }) {
createRoot(el).render(<App {...props} />)
},
})
Vue 3:
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
import { inertia } from '@inertiajs/vite'
createInertiaApp({
resolve: inertia.resolvePages('../pages'),
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})
Svelte:
import { createInertiaApp } from '@inertiajs/svelte'
import { inertia } from '@inertiajs/vite'
createInertiaApp({
resolve: inertia.resolvePages('../pages'),
setup({ el, App }) {
new App({ target: el })
},
})
mkdir -p app/frontend/pages
Create config/initializers/inertia_rails.rb:
# frozen_string_literal: true
InertiaRails.configure do |config|
# Asset versioning
config.version = -> { ViteRuby.digest }
# Flash keys exposed to frontend
config.flash_keys = %i[notice alert]
# Required for Inertia.js v3
config.use_script_element_for_initial_page = true
config.use_data_inertia_head_attribute = true
config.always_include_errors_hash = true
# Deep merge shared data with page props
# config.deep_merge_shared_data = true
# Encrypt history for sensitive data (requires HTTPS)
# config.encrypt_history = Rails.env.production?
end
In app/controllers/application_controller.rb:
class ApplicationController < ActionController::Base
inertia_share do
{
flash: {
notice: flash.notice,
alert: flash.alert
},
auth: {
user: current_user&.as_json(only: [:id, :name, :email])
}
}
end
end
Controller:
# app/controllers/home_controller.rb
class HomeController < ApplicationController
def index
render inertia: { message: 'Welcome to Inertia Rails!' }
end
end
Route:
# config/routes.rb
Rails.application.routes.draw do
root 'home#index'
end
Page Component (React):
// app/frontend/pages/home/index.jsx
export default function Home({ message }) {
return (
<div>
<h1>{message}</h1>
</div>
)
}
Page Component (Vue):
<!-- app/frontend/pages/home/index.vue -->
<script setup>
defineProps(['message'])
</script>
<template>
<div>
<h1>{{ message }}</h1>
</div>
</template>
# Terminal 1: Rails server
bin/rails server
# Terminal 2: Vite dev server
bin/vite dev
| Option | Default | Description |
|---|---|---|
version |
nil |
Asset version for cache busting |
layout |
'application' |
Default layout template |
flash_keys |
[:notice, :alert] |
Flash keys to share |
deep_merge_shared_data |
false |
Deep merge props |
encrypt_history |
false |
Encrypt browser history |
ssr_enabled |
false |
Enable SSR |
ssr_url |
'http://localhost:13714' |
SSR server URL |
default_render |
false |
Auto-render Inertia |
root_dom_id |
'app' |
Root element ID |
use_script_element_for_initial_page |
false |
Use <script> tag for initial page data (required for v3) |
use_data_inertia_head_attribute |
false |
Use data-inertia attribute for head tags (required for v3) |
always_include_errors_hash |
nil |
Always include errors object in page props |
prop_transformer |
identity | Transform prop keys (e.g., camelCase) |
component_path_resolver |
"path/action" |
Custom component name resolution |
parent_controller |
'::ApplicationController' |
Base controller for static routes |
expose_shared_prop_keys |
true |
Include shared prop keys in page metadata |
precognition_prevent_writes |
false |
Prevent DB writes during precognition |
All config options can be set via INERTIA_ prefixed env vars:
INERTIA_SSR_ENABLED=true
INERTIA_ENCRYPT_HISTORY=true
If upgrading an existing Inertia.js v2 project:
Add these to your Inertia Rails initializer:
config.use_script_element_for_initial_page = true
config.use_data_inertia_head_attribute = true
config.always_include_errors_hash = true
axiosAdapter() to keep Axios)invalid โ httpException, exception โ networkErrorrouter.cancel() โ router.cancelAll()inertia โ data-inertianpm install @inertiajs/vite
Update vite.config.js:
import inertia from '@inertiajs/vite'
export default defineConfig({
plugins: [
inertia(),
// ... other plugins
],
})
The Vite plugin provides:
withApp callback for providers/pluginsRun npm install to install dependencies.
Check browser console for JavaScript errors. Ensure Vite dev server is running.
Ensure you're using render inertia: not render json:.
Inertia handles CSRF automatically. Ensure protect_from_forgery is enabled.