xiaohongshu
xiaohongshu
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 ...
Full skill instructions
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.
Use this skill when:
Ask the user for project configuration:
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
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
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:
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"
}
}
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
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
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-client (base) and libpq-dev (build)default-mysql-client (base) and libmysqlclient-dev (build)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:
vite server with init: true and network-alias: vite_ssr optionsINERTIA_SSR_URL: http://vite_ssr:13714 to envRedis/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:
env:
clear:
SOLID_QUEUE_IN_PUMA: true
--skip-solid, OMIT this variableOptional: 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
Verify the setup works:
export RAILS_ENV=production
./bin/rails assets:precompile
Check for successful output:
public/vite-ssr/ssr.js existsInform the user about deployment configuration:
Configure secrets in .env (git-ignored):
POSTGRES_PASSWORD=secure-password
KAMAL_REGISTRY_PASSWORD=docker-hub-token
Update .kamal/secrets:
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
RAILS_MASTER_KEY=$(cat config/master.key)
POSTGRES_PASSWORD=$POSTGRES_PASSWORD
Update config/deploy.yml with actual server IPs and domain
Deploy:
export $(grep -v '^#' .env | xargs)
git add . && git commit -m "Setup Inertia Rails with SSR"
kamal setup
kamal deploy
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
rails assets:precompile (handles both client and SSR, plus npm install)bin/vite build --ssr separately (redundant)npm ci separately (Vite Ruby handles it)Web Container (Rails) ←→ vite_ssr Container (Node.js)
via http://vite_ssr:13714
Fixed hostname via network-alias: vite_ssr enables reliable connection.
pgpostgresql-clientlibpq-devpostgres:18 (latest stable)data:/var/lib/postgresql (BREAKING CHANGE in PostgreSQL 18: previous versions used data:/var/lib/postgresql/data)127.0.0.1:5432:5432POSTGRES_USER, POSTGRES_DB, POSTGRES_PASSWORDmysql2default-mysql-clientlibmysqlclient-devmysql:9.4.0 (latest Innovation) or mysql:8.4 (LTS recommended for production)127.0.0.1:3306:3306MYSQL_ROOT_HOST, MYSQL_DATABASE, MYSQL_USER, MYSQL_ROOT_PASSWORDsqlite3 (default)storage/ directory in Rails 8+# 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"
config/database.yml production section for actual path:
production:
<<: *default
database: storage/production.sqlite3 # Note: stored in storage/ not db/
tsconfig.json and tsconfig.app.json--defaults --yes with shadcn, --no-interactive with inertia:installnetwork-alias: vite_ssr"host": "127.0.0.1", connections to 127.0.0.1 failhost: <%= ENV["DB_HOST"] %> and password for production/rails/storage (not /rails/db) since Rails 8 stores SQLite in storage/ directoryvalkey/valkey:9 image to avoid Redis licensing concernsGemfile.lock to prevent cache invalidationconfig/vite.json has "ssrBuildEnabled": trueapp/frontend/ssr/ssr.tsx existsnpm ci to reinstall dependenciesvite server has network-alias: vite_ssr in deploy.ymlINERTIA_SSR_URL: http://vite_ssr:13714 in envDB_HOST matches accessory service name (e.g., PROJECT_NAME-db)kamal accessory details db.kamal/secrets and config/database.yml@/ prefix: import { Button } from '@/components/ui/button'complete-guide.md - Complete 778-line implementation guide with all variationsdockerfile-ssr-patterns.md - Dockerfile modifications for PostgreSQL/MySQL/SQLitekamal-ssr-deployment.md - Kamal SSR architecture and deployment examplesssr-entry.tsx - SSR server entry point templatedeploy-postgres.yml - PostgreSQL deployment configurationdeploy-mysql.yml - MySQL deployment configurationdeploy-sqlite.yml - SQLite deployment configurationUse these references when detailed examples are needed or when helping users with specific database configurations.
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience