| name | railstart-preset-builder |
| description | Guide for creating railstart preset configuration files. Use when building new presets, customizing Rails 8 app generation, creating team-specific configurations, or defining opinionated Rails stacks. Covers YAML structure, ID-based merging, post-action configuration, and testing presets for the railstart gem. |
Railstart Preset Builder
Purpose
This skill guides you through creating preset configuration files for the railstart gem. Presets enable quick Rails 8 application generation with predefined choices for database, CSS, JavaScript, test framework, and post-generation actions.
When to Use This Skill
Use this skill when:
- Creating new railstart presets for specific tech stacks
- Defining team or organization default configurations
- Building quick-start templates for common Rails patterns
- Customizing Rails app generation workflows
- Setting up opinionated Rails configurations
Preset System Overview
Three-Layer Configuration
Railstart uses a three-layer configuration merge system:
- Base Config (
config/rails8_defaults.yaml) - Defines all available questions and post-actions
- User Config (
~/.config/railstart/config.yaml) - User's personal overrides (optional)
- Preset Config (
config/presets/*.yaml) - Named preset that overrides defaults
Merge Order: Base → User → Preset (later layers win)
ID-Based Merging
Questions and post-actions merge by unique id field:
- Questions with matching IDs have their
choices array replaced entirely
- Individual choice
default flags override base configuration
- Post-actions with matching IDs have their
enabled state overridden
multi_select Defaults
For multi_select questions (like skip_features), always use choice values (stable IDs), not display names:
- id: skip_features
default:
- action_mailer
- action_text
- hotwire
- id: skip_features
default:
- Action Mailer
- Hotwire (Turbo + Stimulus)
Why values are better:
- Stability: Display text can change for UX improvements without breaking presets
- Consistency: Values are used throughout the system (CommandBuilder, answers storage)
- Correctness: Generator automatically transforms values → names for TTY::Prompt display
Available Questions
From config/rails8_defaults.yaml:
Database (select)
- ID:
database
- Choices:
sqlite3, postgresql, mysql
- Default:
sqlite3
- Flag:
--database=%{value}
CSS Framework (select)
- ID:
css
- Choices:
tailwind, bootstrap, bulma, postcss, sass, none
- Default:
tailwind
- Flag:
--css=%{value}
JavaScript Approach (select)
- ID:
javascript
- Choices:
importmap, bun, esbuild, rollup, webpack, vite, none
- Default:
importmap
- Flags: Choice-level flags (e.g.,
--javascript=bun or --skip-javascript)
Test Framework (select)
- ID:
test_framework
- Choices:
minitest, rspec
- Default:
minitest
- Flag: RSpec uses
--skip-test
Skip Features (multi_select)
- ID:
skip_features
- Values:
action_mailer, action_mailbox, action_text, active_record, active_job, active_storage, action_cable, hotwire
- Default:
[] (none skipped)
- Flags: Individual choice flags (e.g.,
--skip-action-mailer)
- Note: Use values in
default array, not display names (see multi_select Defaults section above)
Boolean Options (yes_no)
- IDs:
api_only, skip_git, skip_docker, skip_bundle
- Flags: Various (e.g.,
--api, --skip-git)
Available Post-Actions
init_git
- Default: Enabled if
skip_git = false
- Command:
git init && git add . && git commit -m 'Initial commit'
- Purpose: Initialize git repository
bundle_install
- Default: Disabled
- Condition: Only if
skip_bundle = true
- Command:
bundle install
- Purpose: Manual gem installation
setup_rspec
- Default: Enabled
- Condition: Only if
test_framework = rspec
- Command:
bundle add rspec-rails --group development,test && bundle exec rails generate rspec:install
- Purpose: Automatic RSpec setup
setup_vite
- Default: Enabled
- Condition: Only if
javascript = vite
- Command:
bundle add vite_rails && bundle install && bundle exec vite install
- Purpose: Automatic Vite Rails setup
setup_bundlebun
- Default: Disabled
- Condition: Only if
javascript = bun
- Command:
bundle add bundlebun && bundle install && bundle exec rake bun:install
- Purpose: Optional Bundlebun (Bun as a gem) setup
Preset Creation Workflow
Step 1: Define Requirements
Answer these questions:
- What stack does this preset target? (e.g., "API-only", "Modern SPA", "Traditional Rails")
- Which database? (PostgreSQL for production, SQLite for quick prototypes)
- Which CSS framework? (Tailwind for utility-first, none for APIs)
- Which JavaScript approach? (Vite for SPAs, importmap for traditional, none for APIs)
- Which test framework? (Minitest default, RSpec for BDD)
- Which features to skip? (Action Mailer, Hotwire, etc. for APIs)
- Which post-actions to enable? (Vite setup, Bundlebun, RSpec)
Step 2: Create Preset File
Location: config/presets/{preset-name}.yaml
Naming Convention:
- Lowercase with hyphens
- Descriptive of stack (e.g.,
vite-bun, api-only, default)
- Short and memorable
Basic Structure:
---
questions:
- id: database
choices:
- name: PostgreSQL
value: postgresql
default: true
- id: css
choices:
- name: Tailwind
value: tailwind
default: true
- id: javascript
choices:
- name: Importmap (default)
value: importmap
default: true
- id: test_framework
choices:
- name: Minitest (default)
value: minitest
default: true
- id: skip_features
default: []
- id:
Step 3: Override Defaults
Only include questions you want to override. Minimal example:
---
questions:
- id: database
choices:
- name: PostgreSQL
value: postgresql
default: true
- id: css
choices:
- name: None
value: none
default: true
- id: skip_features
default:
- action_mailer
- action_text
- hotwire
- id: api_only
default: true
post_actions:
- id: init_git
name: "Initialize git repository"
enabled: true
command: "git init && git add . && git commit -m 'Initial commit'"
Step 4: Enable Post-Actions
Enable relevant post-actions based on your choices. IMPORTANT: Always include complete post-action definitions with name and command:
post_actions:
- id: setup_vite
name: "Setup Vite Rails"
enabled: true
command: "bundle add vite_rails && bundle install && bundle exec vite install"
- id: setup_bundlebun
name: "Setup Bundlebun (Bun packaged as a gem)"
enabled: true
command: "bundle add bundlebun && bundle install && bundle exec rake bun:install"
- id: setup_rspec
name: "Setup RSpec"
enabled: true
command: "bundle add rspec-rails --group development,test && bundle exec rails generate rspec:install"
Step 5: Test Preset
Manual Testing:
ruby -ryaml -e "puts YAML.load_file('config/presets/your-preset.yaml').inspect"
bundle exec exe/railstart new testapp --preset your-preset --default
cd testapp
cat Gemfile
ls -la
Automated Testing:
bundle exec rake test
bundle exec rubocop
Real-World Examples
Example 1: Modern SPA Stack (vite-bun.yaml)
---
questions:
- id: database
choices:
- name: PostgreSQL
value: postgresql
default: true
- id: css
choices:
- name: Tailwind
value: tailwind
default: true
- id: javascript
choices:
- name: Vite (via vite_rails gem)
value: vite
default: true
- id: test_framework
choices:
- name: Minitest (default)
value: minitest
default: true
- id: skip_features
default: []
-
Use Case: Building modern SPAs with fast HMR (Vite) and unified JavaScript runtime (Bundlebun)
Usage:
railstart new myapp --preset vite-bun
Example 2: API-Only Stack (api-only.yaml)
---
questions:
- id: database
choices:
- name: PostgreSQL
value: postgresql
default: true
- id: css
choices:
- name: None
value: none
default: true
- id: javascript
choices:
- name: Importmap (default)
value: importmap
default: true
- id: skip_features
default:
- action_mailer
- action_text
- hotwire
- id: api_only
default: true
- id: skip_git
default: false
Use Case: Building JSON APIs without views or frontend assets
Usage:
railstart new api --preset api-only
Example 3: RSpec + PostgreSQL Stack
---
questions:
- id: database
choices:
- name: PostgreSQL
value: postgresql
default: true
- id: test_framework
choices:
- name: RSpec
value: rspec
default: true
- id: skip_git
default: false
post_actions:
- id: init_git
name: "Initialize git repository"
enabled: true
command: "git init && git add . && git commit -m 'Initial commit'"
- id: setup_rspec
name: "Setup RSpec"
enabled: true
command: "bundle add rspec-rails --group development,test && bundle exec rails generate rspec:install"
Use Case: Teams preferring RSpec over Minitest for BDD-style testing
Usage:
railstart new myapp --preset rspec
Best Practices
Naming
✅ DO:
- Use descriptive hyphenated names (
vite-bun, api-only)
- Keep names short and memorable
- Use stack technology names when relevant
❌ DON'T:
- Use underscores or spaces
- Use overly generic names (
preset1, test)
- Use version numbers unless necessary
Documentation
✅ DO:
- Add clear comments explaining the preset's purpose
- Document when to use this preset
- Explain non-obvious choices
❌ DON'T:
- Leave presets undocumented
- Assume users know why choices were made
Scope
✅ DO:
- Override only what's necessary for the stack
- Leave unrelated options at defaults
- Enable relevant post-actions
❌ DON'T:
- Override every single option
- Enable unrelated post-actions
- Create overly complex presets
Testing
✅ DO:
- Test YAML syntax before committing
- Generate test apps with the preset
- Verify all post-actions execute correctly
- Check generated Gemfile and config files
❌ DON'T:
- Commit untested presets
- Assume merging works without verification
- Skip validation of post-action commands
Common Patterns
Pattern 1: PostgreSQL + Tailwind (Production Default)
Most production apps benefit from:
questions:
- id: database
choices:
- name: PostgreSQL
value: postgresql
default: true
- id: css
choices:
- name: Tailwind
value: tailwind
default: true
Pattern 2: Skip All Frontend (Pure API)
API-only apps should skip frontend tooling:
questions:
- id: css
choices:
- name: None (skip CSS setup)
value: none
default: true
- id: javascript
choices:
- name: None (skip JavaScript)
value: none
default: true
- id: skip_features
default:
- action_mailer
- action_text
- hotwire
- id: api_only
default: true
Pattern 3: Modern Frontend Stack
SPAs and modern frontends typically use:
questions:
- id: javascript
choices:
- name: Vite (via vite_rails gem)
value: vite
default: true
post_actions:
- id: setup_vite
enabled: true
Troubleshooting
Preset Not Loading
Symptom: Preset file ignored, defaults used
Solutions:
- Verify file location:
config/presets/{name}.yaml
- Check YAML syntax:
ruby -ryaml -e "YAML.load_file('config/presets/name.yaml')"
- Ensure preset name matches filename (without .yaml)
- Check for typos in
--preset flag
Wrong Defaults Selected
Symptom: Different choice selected than expected
Solutions:
- Verify
default: true is on the correct choice
- Check for multiple
default: true in same question (last wins)
- Ensure question
id matches exactly
- Test ID-based merging manually
Post-Action Not Running
Symptom: Expected post-action skipped
Solutions:
- Check
enabled: true in preset
- Verify conditional logic (
if field) matches selected answers
- Ensure post-action
id matches exactly
- Check command syntax for errors
YAML Syntax Error
Symptom: Parse error or invalid YAML
Solutions:
- Validate YAML:
yq . config/presets/name.yaml
- Check indentation (2 spaces, no tabs)
- Ensure proper array syntax (
- item)
- Verify all strings are properly quoted if containing special chars
Quick Reference
Minimal Preset Template
---
questions:
- id: database
choices:
- name: PostgreSQL
value: postgresql
default: true
post_actions:
- id: init_git
enabled: true
Usage Commands
ls config/presets/
railstart new myapp --preset name
railstart new myapp --preset name --default
ruby -ryaml -e "puts YAML.load_file('config/presets/name.yaml').inspect"
Testing Checklist
Status: Complete - Ready for use ✅
Version: 1.0.0
Last Updated: 2025-11-22