Awesome-omni-skill rails-inertia-stack
Generate production-ready Rails applications with Inertia.js, React, TypeScript, Server-Side Rendering (SSR), and ShadcnUI components, configured for deployment with Kamal. Use when creating new Rails projects that need modern SPA-like frontend with SEO-friendly SSR, or when helping users set up Inertia.js with Rails. Supports PostgreSQL, MySQL, and SQLite databases.
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/development/rails-inertia-stack-darkamenosa" ~/.claude/skills/diegosouzapw-awesome-omni-skill-rails-inertia-stack && rm -rf "$T"
skills/development/rails-inertia-stack-darkamenosa/SKILL.mdRails Inertia Stack Generator
Overview
Generate complete, production-ready Rails applications with Inertia.js for SPA-like user experience, React + TypeScript frontend, Server-Side Rendering for SEO, ShadcnUI component library, and Kamal deployment configuration. The skill handles the entire setup process including Dockerfile configuration for SSR, database accessories, and deployment configuration.
When to Use This Skill
Use this skill when:
- Creating new Rails projects with modern frontend stack
- Setting up Inertia.js with React and TypeScript in Rails
- Configuring Server-Side Rendering for Rails + Inertia applications
- Setting up ShadcnUI with Rails projects
- Preparing Rails applications for Kamal deployment
- Migrating between databases (PostgreSQL/MySQL/SQLite)
Core Workflow
Step 1: Determine Project Requirements
Ask the user for project configuration:
- Project name (required)
- Database choice: PostgreSQL (recommended for production), MySQL, or SQLite
- Server IP addresses for deployment (can be configured later)
- Domain name for SSL (optional, can be configured later)
Step 2: Create Rails Project
Execute the appropriate Rails new command based on database choice:
PostgreSQL:
rails new PROJECT_NAME -d postgresql --skip-javascript cd PROJECT_NAME
MySQL:
rails new PROJECT_NAME -d mysql --skip-javascript cd PROJECT_NAME
SQLite:
# Default with Solid stack rails new PROJECT_NAME --skip-javascript cd PROJECT_NAME # Or without Solid stack (if user requests) rails new PROJECT_NAME --skip-javascript --skip-solid cd PROJECT_NAME
Step 3: Install Inertia Rails Stack
Run these commands in sequence:
# Add Inertia Rails gem bundle add inertia_rails # Install frontend stack (non-interactive) bin/rails generate inertia:install \ --framework=react \ --typescript \ --vite \ --tailwind \ --no-interactive
When prompted about bin/dev conflict: Choose
Y to overwrite.
After installation:
# Setup databases bin/rails db:setup bin/rails db:migrate
Step 4: Configure RuboCop (Optional but Recommended)
Rails 8 includes RuboCop Rails Omakase by default. Create or update
.rubocop.yml:
# Omakase Ruby styling for Rails inherit_gem: { rubocop-rails-omakase: rubocop.yml } # Overwrite or add rules to create your own house style # # # Use `[a, [b, c]]` not `[ a, [ b, c ] ]` # Layout/SpaceInsideArrayLiteralBrackets: # Enabled: false # Restore strict 2-space indentation enforcement Layout/IndentationConsistency: Enabled: true Layout/IndentationWidth: Enabled: true Width: 2
Why this matters:
- Maintains consistent code style across the project
- Omakase provides sensible Rails defaults
- Strict 2-space indentation ensures readability
Step 5: Fix Development Configuration
Apply two critical fixes for development:
Fix 1: Procfile.dev (ensure Rails runs on port 3000)
Read
Procfile.dev and swap the order:
web: bin/rails s vite: bin/vite dev
Fix 2: config/vite.json (enable 127.0.0.1 access)
Add
"host": "127.0.0.1" to development section:
{ "development": { "autoBuild": true, "publicOutputDir": "vite-dev", "port": 3036, "host": "127.0.0.1" } }
Step 6: Setup ShadcnUI
Configure TypeScript for ShadcnUI (CRITICAL: update BOTH files):
tsconfig.app.json - Add to compilerOptions:
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./app/frontend/*"] } } }
tsconfig.json - Add to root:
{ "compilerOptions": { "baseUrl": "./app/frontend", "paths": { "@/*": ["./*"] } } }
Initialize ShadcnUI (non-interactive):
npx shadcn@latest init --defaults --yes npx shadcn@latest add button --yes --overwrite
Step 7: Configure Server-Side Rendering (SSR)
Create SSR entry point at
app/frontend/ssr/ssr.tsx:
import { createInertiaApp } from '@inertiajs/react' import createServer from '@inertiajs/react/server' import ReactDOMServer from 'react-dom/server' createServer((page) => createInertiaApp({ page, render: ReactDOMServer.renderToString, resolve: (name) => { const pages = import.meta.glob('../pages/**/*.tsx', { eager: true }) return pages[`../pages/${name}.tsx`] }, setup: ({ App, props }) => <App {...props} />, }), )
Enable client-side hydration in
app/frontend/entrypoints/inertia.ts:
Add
hydrateRoot import:
import { createRoot, hydrateRoot } from 'react-dom/client'
Update setup function:
setup({ el, App, props }) { if (el) { if (import.meta.env.MODE === "production") { hydrateRoot(el, createElement(App, props)) } else { createRoot(el).render(createElement(App, props)) } } else { console.error('Missing root element...') } }
Enable SSR in Vite - Add to
config/vite.json:
{ "production": { "ssrBuildEnabled": true } }
Enable SSR in Inertia Rails - Update
config/initializers/inertia_rails.rb:
InertiaRails.configure do |config| config.version = ViteRuby.digest config.encrypt_history = true config.always_include_errors_hash = true config.ssr_enabled = ViteRuby.config.ssr_build_enabled end
Step 8: Configure Dockerfile for SSR
TWO modifications needed to the generated Dockerfile!
Reference
references/dockerfile-ssr-patterns.md for complete examples.
Modification 1: Install Node.js in BASE stage
Add AFTER "Install base packages", BEFORE bundler installation:
# Install JavaScript runtime (prebuilt Node per-arch) ARG NODE_VERSION=25.0.0 ARG TARGETARCH ENV PATH=/usr/local/node/bin:$PATH RUN apt-get update -qq && \ apt-get install --no-install-recommends -y xz-utils && \ case "${TARGETARCH}" in \ amd64) NODEARCH=x64 ;; \ arm64) NODEARCH=arm64 ;; \ *) echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \ esac && \ mkdir -p /usr/local/node && \ curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${NODEARCH}.tar.xz" | \ tar -xJ -C /usr/local/node --strip-components=1 && \ /usr/local/node/bin/node -v && \ /usr/local/node/bin/npm -v && \ apt-get purge -y --auto-remove xz-utils && \ rm -rf /var/lib/apt/lists /var/cache/apt/archives
Modification 2: Install Bundler with Locked Version
Add AFTER Node.js installation, BEFORE "Set production environment":
# Ensure the Bundler version matches Gemfile.lock to avoid per-build upgrades. RUN gem install bundler -v 2.7.2 -N
Important: Check
Gemfile.lock bottom section for BUNDLED WITH version and update to match:
tail Gemfile.lock # BUNDLED WITH # 2.7.2
That's all! No changes to BUILD stage (Vite Ruby handles npm install), no changes to final stage, no EXPOSE, no CMD modifications.
Database client variations - adjust base packages only:
- PostgreSQL:
(base) andpostgresql-client
(build)libpq-dev - MySQL:
(base) anddefault-mysql-client
(build)libmysqlclient-dev - SQLite: No database client needed
Step 9: Configure Kamal Deployment
Update
config/deploy.yml with SSR and database configuration.
Reference
references/kamal-ssr-deployment.md and references/complete-guide.md for detailed examples.
Key additions:
- Add
server withvite
andinit: true
optionsnetwork-alias: vite_ssr - Add
to envINERTIA_SSR_URL: http://vite_ssr:13714 - Configure database accessory (PostgreSQL/MySQL) or volumes (SQLite)
- Update database environment variables
- (Optional) Add Redis/Valkey accessory if needed for caching, queues, or Action Cable
Redis/Valkey Configuration (if requested): Use Valkey instead of Redis due to licensing concerns:
accessories: redis: image: valkey/valkey:9 # Use Valkey, not redis image host: SERVER_IP port: "127.0.0.1:6379:6379" directories: - redis_data:/data env: clear: REDIS_URL: redis://PROJECT_NAME-redis:6379/1
Solid Queue Configuration:
- If user created project WITH Solid (default), include:
env: clear: SOLID_QUEUE_IN_PUMA: true - If user created project with
, OMIT this variable--skip-solid
Optional: Async Job Server (Advanced): For dedicated job processing (alternative to
SOLID_QUEUE_IN_PUMA), add a job server:
servers: job: hosts: - SERVER_IP cmd: bundle exec async-job-adapter-active_job-server
This runs jobs in a separate container for better resource isolation.
Create database initialization file at
db/production.sql:
CREATE DATABASE PROJECT_NAME_production_cache; CREATE DATABASE PROJECT_NAME_production_queue; CREATE DATABASE PROJECT_NAME_production_cable;
Update database.yml production section:
production: primary: &primary_production <<: *default host: <%= ENV["DB_HOST"] %> database: PROJECT_NAME_production username: PROJECT_NAME password: <%= ENV["POSTGRES_PASSWORD"] %> # or MYSQL_ROOT_PASSWORD
Step 10: Test SSR Build
Verify the setup works:
export RAILS_ENV=production ./bin/rails assets:precompile
Check for successful output:
- Client bundle build completes
- SSR bundle build completes
existspublic/vite-ssr/ssr.js
Step 11: Provide Deployment Instructions
Inform the user about deployment configuration:
-
Configure secrets in
(git-ignored):.envPOSTGRES_PASSWORD=secure-password KAMAL_REGISTRY_PASSWORD=docker-hub-token -
Update
:.kamal/secretsKAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD RAILS_MASTER_KEY=$(cat config/master.key) POSTGRES_PASSWORD=$POSTGRES_PASSWORD -
Update
with actual server IPs and domainconfig/deploy.yml -
Deploy:
export $(grep -v '^#' .env | xargs) git add . && git commit -m "Setup Inertia Rails with SSR" kamal setup kamal deploy
Critical Patterns
Non-Interactive Installation
Always use these flags to avoid prompts:
# ShadcnUI initialization npx shadcn@latest init --defaults --yes npx shadcn@latest add COMPONENT --yes --overwrite # Inertia installation bin/rails generate inertia:install --no-interactive
SSR Build Process
- ✅ Use
(handles both client and SSR, plus npm install)rails assets:precompile - ❌ Do NOT run
separately (redundant)bin/vite build --ssr - ❌ Do NOT run
separately (Vite Ruby handles it)npm ci
Dockerfile Node.js
- ✅ Install Node.js in base stage using prebuilt binaries (supports multi-arch)
- ✅ Node.js automatically included in final stage
- ❌ Do NOT remove Node.js after build (breaks SSR)
- ❌ Do NOT run npm ci separately (Vite Ruby handles it)
Kamal SSR Architecture
Web Container (Rails) ←→ vite_ssr Container (Node.js) via http://vite_ssr:13714
Fixed hostname via
network-alias: vite_ssr enables reliable connection.
Database-Specific Variations
PostgreSQL (Production Recommended)
- Gem:
pg - Dockerfile client:
postgresql-client - Dockerfile build lib:
libpq-dev - Accessory image:
(latest stable)postgres:18 - Volume mount:
(BREAKING CHANGE in PostgreSQL 18: previous versions useddata:/var/lib/postgresql
)data:/var/lib/postgresql/data - Port:
127.0.0.1:5432:5432 - Env vars:
,POSTGRES_USER
,POSTGRES_DBPOSTGRES_PASSWORD
MySQL
- Gem:
mysql2 - Dockerfile client:
default-mysql-client - Dockerfile build lib:
libmysqlclient-dev - Accessory image:
(latest Innovation) ormysql:9.4.0
(LTS recommended for production)mysql:8.4 - Port:
127.0.0.1:3306:3306 - Env vars:
,MYSQL_ROOT_HOST
,MYSQL_DATABASE
,MYSQL_USERMYSQL_ROOT_PASSWORD
SQLite (Development/Small Apps)
- Gem:
(default)sqlite3 - Dockerfile: No database client needed
- Deployment: Use volumes instead of accessory
- Important: SQLite databases are stored in
directory in Rails 8+storage/ - Volume configuration:
# CORRECT: Mount storage directory (contains production.sqlite3) volumes: - "PROJECT_NAME_storage:/rails/storage" # INCORRECT: Do not mount db directory # volumes: # - "PROJECT_NAME_db:/rails/db" - Database location: Check
production section for actual path:config/database.ymlproduction: <<: *default database: storage/production.sqlite3 # Note: stored in storage/ not db/
Common Pitfalls to Avoid
- Missing BOTH tsconfig updates - ShadcnUI requires updating both
andtsconfig.jsontsconfig.app.json - Interactive commands - Always use
with shadcn,--defaults --yes
with inertia:install--no-interactive - Removing Node.js from Dockerfile - Node.js must remain in production for SSR
- Missing network-alias - Rails cannot connect to SSR without
network-alias: vite_ssr - Wrong Procfile.dev order - Vite first causes Rails to run on port 3100 instead of 3000
- Missing vite.json host - Without
, connections to 127.0.0.1 fail"host": "127.0.0.1" - Not updating database.yml - Must add
and password for productionhost: <%= ENV["DB_HOST"] %> - Wrong SQLite volume path - Must mount
(not/rails/storage
) since Rails 8 stores SQLite in storage/ directory/rails/db - Using Redis image instead of Valkey - Use
image to avoid Redis licensing concernsvalkey/valkey:9 - Bundler version mismatch - Must lock bundler version in Dockerfile to match
to prevent cache invalidationGemfile.lock
Troubleshooting
SSR Build Fails
- Check Node.js is in Dockerfile base stage
- Verify
hasconfig/vite.json"ssrBuildEnabled": true - Ensure
existsapp/frontend/ssr/ssr.tsx - Run
to reinstall dependenciesnpm ci
Rails Can't Connect to SSR
- Verify
server hasvite
in deploy.ymlnetwork-alias: vite_ssr - Check
in envINERTIA_SSR_URL: http://vite_ssr:13714 - Ensure both web and vite containers are on same network
Database Connection Fails
- Verify
matches accessory service name (e.g.,DB_HOST
)PROJECT_NAME-db - Check database accessory is running:
kamal accessory details db - Confirm password matches between
and.kamal/secretsconfig/database.yml
ShadcnUI Components Not Resolving
- Verify BOTH tsconfig files have path aliases
- Ensure imports use
prefix:@/import { Button } from '@/components/ui/button'
Resources
references/
- Complete 778-line implementation guide with all variationscomplete-guide.md
- Dockerfile modifications for PostgreSQL/MySQL/SQLitedockerfile-ssr-patterns.md
- Kamal SSR architecture and deployment exampleskamal-ssr-deployment.md
assets/
- SSR server entry point templatessr-entry.tsx
- PostgreSQL deployment configurationdeploy-postgres.yml
- MySQL deployment configurationdeploy-mysql.yml
- SQLite deployment configurationdeploy-sqlite.yml
Use these references when detailed examples are needed or when helping users with specific database configurations.