https://<app>.on.getfloo.com, with managed Postgres, signed-in users, and your own domain.
New to floo? Start with the Quickstart.
Before you start
You need:- A Rails 7+ project (or a fresh
rails new). - The project pushed to a GitHub repository (public or private). floo pulls source from GitHub; it does not upload local files.
- The floo CLI installed and authenticated (
curl -fsSL https://getfloo.com/install.sh | bashthenfloo auth login). - The floo GitHub App installed on the account that owns the repository.
floo apps github connectopens a browser to install it if it is missing.
1. Add a Dockerfile
Rails 7.1+ ships with a production-readyDockerfile from rails new. If yours doesn’t, generate one:
Dockerfile
RAILS_ENV=production is set before assets:precompile so the production asset pipeline runs, and SECRET_KEY_BASE_DUMMY=1 lets Rails 7.1+ precompile without the real secret, which is not available at build time.
2. Initialize the floo config
From the repo root:floo.app.toml. For a single-service Rails app it looks like:
floo.app.toml
migrate_command runs as a one-off job with the new image before traffic shifts, on every dev deploy and every promote; a failed migration is logged as a warning and the rollout continues, except on a promote that reuses the dev image (no NEXT_PUBLIC_/VITE_/REACT_APP_ vars in prod), where it fails the promote before prod changes.
3. Connect the repo and deploy
github connect does three things:
- Creates the floo app if it doesn’t exist.
- Wires the GitHub repo as the source.
- Triggers the first deploy.
Your Rails app is live at
https://my-rails-app-dev.on.getfloo.com.Every git push origin main ships to dev. floo releases promote --app my-rails-app publishes to https://my-rails-app.on.getfloo.com.4. Add a Postgres database
floo.app.toml
DATABASE_URL plus standard PG* component variables. Commit it so reviewers see managed-service intent alongside code:
DATABASE_URL automatically. Confirm config/database.yml has the production block:
config/database.yml
bin/rails db:migrate against the new database before traffic shifts. Dev and prod each get isolated schemas and credentials: no shared state, no cross-environment leaks.
DATABASE_URL is a normal PostgreSQL URI, so Rails/ActiveRecord can parse it directly. You do not need custom socket parsing in config/database.yml.
floo preflight also warns if a local env file still contains the old socket-style DATABASE_URL shape (postgresql://user:pass@/db?host=/cloudsql/...), which Ruby’s URI parser rejects before Rails can boot.
Need embeddings? Managed Postgres ships with pgvector enabled, declare a bare vector column (t.vector :embedding, limit: 1536, or the neighbor gem) with no CREATE EXTENSION step. See Postgres → Vector search.
5. Add Redis (cache, jobs, Action Cable)
floo.app.toml
REDIS_URL_CACHE (a rediss:// URL). One instance can back Rails cache, Sidekiq, and Action Cable at once:
config/environments/production.rb
config/initializers/sidekiq.rb
config/cable.yml
web and worker declare redis:cache, so floo injects the same REDIS_URL_CACHE into both. A worker takes no HTTP traffic, but floo preflight still requires a port on every inline service, so declare one and leave ingress internal. Because the worker shares the web build, it must also declare its own command:
floo.app.toml
[managed.cache], [managed.queue]) and read REDIS_URL_CACHE / REDIS_URL_QUEUE. See Redis.
6. Add file storage (Active Storage)
floo.app.toml
STORAGE_BUCKET_UPLOADS. Attach it with managed = ["storage:uploads"]. floo runs your container as a service account with read/write on that bucket, so Active Storage’s google service authenticates automatically via Application Default Credentials, with no key file or project::
config/storage.yml
config/environments/production.rb
rails_storage_proxy, above). floo grants the app read/write but not URL-signing, so Active Storage’s default redirect-mode serving and browser direct uploads won’t work, proxy mode streams blobs through your app and has_one_attached uploads go through your controllers, both server-side and signing-free. Don’t use Active Storage :amazon / S3 SDKs; floo mints no S3 keys. Full contract: Cloud storage.
7. Add per-user auth
floo manages user authentication for you. Setaccess_mode = "accounts" in floo.app.toml:
floo.app.toml
- Redirects unauthenticated requests to a hosted login page.
- Validates the session cookie on every request.
- Injects identity headers into every request that reaches your Rails app.
app/controllers/application_controller.rb
floo dev --fixture-user (see section 9), it injects the same X-Floo-User-* headers floo’s gateway adds in production, so the controller above works locally without any conditional code.
For the full reference on access modes and identity headers, see Auth.
8. Add a custom domain
app.example.com to edge.getfloo.com and the _floo-verify TXT claim token. Once they propagate, click Verify DNS in the dashboard or run floo domains verify app.example.com --app my-rails-app.
If your app needs request.host to match the custom domain (for redirects, mailer URLs, etc.), Rails reads it from the Host header automatically: no extra config needed.
9. Local development with dev credentials
Once your first deploy is up, you don’t need to redeploy to iterate. Two commands cover the daily Rails workflow.Local dev server
dev_command (the bin/rails server line in floo.app.toml) locally with DATABASE_URL and the other env vars from the app’s dev environment: a real connection to your dev Postgres from your laptop, with no credentials in your shell history. Prod credentials are never handed to a local session.
To test signed-in flows without writing a fixture-user shim in your Rails code, add --fixture-user:
floo dev then starts a small proxy in front of each accounts-mode service that injects the same X-Floo-User-* headers floo’s gateway adds in production. The output table shows both the raw service URL and the auth-proxied URL. Hit the auth-proxied one when testing dashboard/profile/etc. paths.
One-shot commands: rake tasks, console, db:seed
floo run executes a single command with the same dev-environment env vars floo dev injects: no server, only the command. Pass the command after --:
floo run inherits stdin/stdout/stderr, so interactive commands like bin/rails console and byebug work the same as running them locally, the only difference is your shell sees the floo-injected env vars instead of whatever’s in your local .env.
Common gotchas
/healthzis reserved. floo’s edge intercepts that exact path. Use/healthor/livezfor health checks.bind: 0.0.0.0, notlocalhost. Rails binds to localhost by default in some configs, which floo cannot reach.- Asset compilation.
RAILS_SERVE_STATIC_FILES=1is set in the Dockerfile above so Rails serves precompiled assets directly. For high-traffic apps, push assets to floo’s storage service or a CDN. - Force-SSL. Rails 7+ defaults
config.force_ssl = truein production. floo’s edge handles TLS termination and forwardsX-Forwarded-Proto: https, so this works correctly without extra config. - Schema dumps. Each environment gets its own Postgres schema (
app_<id>_dev/_prod); thesearch_pathresolves your unqualified table names, so migrations need no changes. If you switch toconfig.active_record.schema_format = :sql, keep migrations schema-agnostic, astructure.sqldumped from one environment embeds that environment’s schema name. The default:rubyformat (schema.rb) avoids this.
What’s next
Auth, full reference
Identity headers, access policies, and access modes in detail.
Managed services
Postgres, Redis, Storage: what they cost and how isolation works.
Custom domains
DNS, verification, multi-service routing.
Environments
Dev vs prod, promotion, env overrides.