RailsFast Native Quickstart
This is the fastest path from "I have RailsFast Native access" to a real Rails server running inside both native shells.
RailsFast Native has three repos:
railsfast-base— the Rails app and native server contractrailsfast-android— the Android shellrailsfast-ios— the iOS shell
The native apps are not standalone demos. They render your Rails app, start at /native/entry, load path configuration from Rails, and use the same Devise session cookie as the web app.
1. Clone The Repos With The Right Remotes
Start with the normal RailsFast Base quickstart. The important remote convention is: keep the template remote named railsfast, and put your private downstream repo on origin.
git clone --origin railsfast https://github.com/railsfast/railsfast-base.git myapp
cd myapp
git remote add origin https://github.com/YOUR-USERNAME/myapp.git
git push -u origin main
Do the same for the native repos:
git clone --origin railsfast https://github.com/railsfast/railsfast-android.git myapp-android
cd myapp-android
git remote add origin https://github.com/YOUR-USERNAME/myapp-android.git
git push -u origin main
git clone --origin railsfast https://github.com/railsfast/railsfast-ios.git myapp-ios
cd myapp-ios
git remote add origin https://github.com/YOUR-USERNAME/myapp-ios.git
git push -u origin main
Keep the downstream repos private. RailsFast template repos must not be published publicly.
This remote layout is intentional. Later, you can fetch template updates from railsfast and push your product work to origin without confusing the two histories.
2. Get Rails Running First
Finish the RailsFast Base setup before debugging native:
cd myapp
bin/railsfast init
bin/dev
Confirm these URLs exist while the server is running:
curl -I http://localhost:3000/native/entry
curl -I http://localhost:3000/native/configurations/ios/v1.json
curl -I http://localhost:3000/native/configurations/android/v1.json
curl -I http://localhost:3000/.well-known/railsfast.json
If /native/entry is broken, fix Rails first. The native shells only present the server contract; they cannot repair missing routes, bad auth redirects, or invalid path configuration.
3. Run Android
Android emulator networking is different from your Mac's browser. The emulator reaches the Rails server on your Mac through http://10.0.2.2:3000, not localhost.
cd myapp-android
./gradlew installDebug
To point at another server:
./gradlew installDebug -PrailsfastBaseUrl=https://app.example.com
Make the Android app yours with the rename script:
bin/rename \
--package com.example.myapp \
--app-name "My App" \
--base-url https://app.example.com \
--commit
If you want the rename script to also update Rails' native Android package setting, pass the absolute path to your Rails config:
bin/rename \
--package com.example.myapp \
--app-name "My App" \
--base-url https://app.example.com \
--railsfast-config /absolute/path/to/myapp/config/railsfast/railsfast.yml \
--commit
Use a real HTTPS domain before testing Android App Links. Local hosts can be opened with an explicit adb intent, but they cannot pass Android App Links verification.
4. Run iOS
The iOS project is generated from project.yml with XcodeGen. After every project.yml identity change, regenerate before opening Xcode.
cd myapp-ios
brew install xcodegen
xcodegen generate
open RailsFast.xcodeproj
For local Rails development, the simulator can use http://localhost:3000; NSAllowsLocalNetworking is already set. For staging or production, edit RAILSFAST_BASE_URL in project.yml, then regenerate.
Run the test suite on an iOS 26 simulator when you touch shell behavior:
xcodebuild test \
-project RailsFast.xcodeproj \
-scheme RailsFast \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro,OS=26.3.1' \
CODE_SIGNING_ALLOWED=NO
If Xcode reports multiple or missing simulators for a name + OS destination, use a concrete simulator UDID instead: xcrun simctl list devices available, then pass -destination "platform=iOS Simulator,id=<UDID>". RailsFast iOS CI does this because hosted runner images change their pre-created simulator list over time.
Make the iOS app yours in project.yml:
- app display name
- bundle identifier
RAILSFAST_BASE_URLRAILSFAST_ASSOCIATED_DOMAIN- custom URL scheme
- Apple Team ID/signing settings when you are ready for devices and TestFlight
Before a TestFlight/App Store upload, bump the source-controlled iOS version settings from the iOS repo root:
ruby scripts/ios_release_version
Use ruby scripts/ios_release_version --bump none for another TestFlight build
of the same public version. The script updates MARKETING_VERSION and
CURRENT_PROJECT_VERSION in project.yml, runs xcodegen generate, and leaves
the generated Xcode project ready to commit. Do not edit Version or Build only
in Xcode on the signing Mac; XcodeGen will overwrite those Xcode-only edits the
next time the project is regenerated.
Keep the user-agent layering intact. Your app name is app-specific; the RailsFast Native iOS / RailsFast Native Android segments are template identity and Rails uses them for native detection.
Before shipping either shell, generate the installed launcher icons and launch surfaces from the same canonical brand artwork. Follow App Icons and Launch Screens for the exact iOS asset-catalog, Android adaptive-icon, cache-reset, and cold-launch verification workflow.
5. Configure Production Links
Universal Links and Android App Links require both sides:
- the native binary claims the domain
- Rails serves the matching well-known file over real HTTPS
RailsFast Base serves:
/.well-known/assetlinks.json/.well-known/apple-app-site-association/apple-app-site-association
The endpoints intentionally fail closed until you configure real app identity. Android returns [] until a package name and SHA-256 fingerprint exist. iOS returns a valid non-claiming AASA payload until Team ID, bundle/app IDs, and path claims exist.
For iOS, configure the app IDs and path list with IOS_APP_LINK_TEAM_ID, IOS_APP_LINK_BUNDLE_ID, IOS_APP_LINK_APP_IDS, IOS_APP_LINK_PATHS, or native.ios.app_link_paths in config/railsfast/railsfast.yml.
For Android, configure the package name and release signing fingerprint before expecting Chrome-to-app auto-open to work.
Restart Rails after editing config/railsfast/railsfast.yml; it is app configuration, not hot-reloaded page content.
Do not claim /* by default. Claim only the paths the native app should open. Product, marketing, legal, support, billing, and auth URLs may need different behavior.
6. Verify The Real Flows
Before you call the native setup done, test these on both platforms:
- cold launch lands on
/native/entry - signed-out welcome screen opens
- sign-in and sign-up open as native sheets/modals
- bad credentials stay on the form and show the right validation message
- successful auth goes through
/native/handoffand closes the auth shell - logout returns to the signed-out shell
- onboarding users stay outside tabs
- signed-in users reach the tab shell
/dashboard,/native/me,/settings,/organizations,/memberships,/invitations, and/billingstay in their expected tab families- native toasts render for bridge-capable clients, while HTML flash remains the fallback
- a native JSON
401returns to auth instead of leaving the shell stuck - Android works with at least one emulator
- iOS works on iOS 18 and iOS 26 if your deployment range spans both visual systems
Gotchas To Keep In Mind
- Rails owns product rules. Native owns container behavior.
- Path configuration is the routing source of truth; bundled native JSON files are fallbacks, not a second product contract.
- Query strings do not decide tab ownership. Route-family matching is path-based.
- iOS and Android share
settings.shell, but theirrules[]arrays are platform-specific. - Auth success goes to
/native/handoff, not directly to/dashboardand not back through the auth sheet. - Bridge markup is gated by advertised bridge-component support in the user agent, not by platform name.
- Cookie sharing solves authentication continuity, not CSRF. Native writes need an explicit server-side CSRF policy.
- Android's emulator host is
10.0.2.2; iOS Simulator can uselocalhost. - iOS app identity is generated from
project.yml; runxcodegen generateafter changing it. - iOS release version/build numbers are generated from
project.yml; useruby scripts/ios_release_versioninstead of editing Xcode on the signing Mac. - Native billing is intentionally not enabled by default. Do not expose web pricing or checkout inside the native apps until you have a real App Store / Play billing strategy.
References
- Hotwire Native path configuration: https://native.hotwired.dev/overview/path-configuration
- Hotwire Native bridge components: https://native.hotwired.dev/overview/bridge-components
- Hotwire Native iOS configuration: https://native.hotwired.dev/ios/configuration
- Android emulator networking: https://developer.android.com/studio/run/emulator-networking-address
- Android App Links verification: https://developer.android.com/training/app-links/verify-android-applinks
- Apple Associated Domains: https://developer.apple.com/documentation/xcode/supporting-associated-domains
- Apple Universal Links debugging: https://developer.apple.com/documentation/technotes/tn3155-debugging-universal-links
- Apple Info.plist version keys: https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
- Apple
agvtoolversioning reference: https://developer.apple.com/library/archive/qa/qa1827/_index.html - App Store Connect API builds: https://developer.apple.com/documentation/appstoreconnectapi/builds
- fastlane latest TestFlight build number: https://docs.fastlane.tools/actions/latest_testflight_build_number/
- XcodeGen project spec: https://yonaskolb.github.io/XcodeGen/Docs/ProjectSpec.html
- GitHub macOS runner image matrix: https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md
Next
- Native Overview for the mental model.
- RailsFast Base for Native for the server contract.
- RailsFast Android for Android internals.
- RailsFast iOS for iOS internals.
- Customization Workflow for deciding where changes belong.
- App Icons and Launch Screens for native branding assets and launch verification.