floo.app.toml. The next deploy provisions it and injects
the connection values. See Managed services for the
shared lifecycle: declaring, attaching credentials, and removal.
floo.app.toml
What gets injected
Default Postgres providesDATABASE_URL plus PGHOST, PGPORT, PGDATABASE,
PGUSER, and PGPASSWORD.
DATABASE_URL is a plain PostgreSQL URI
(postgresql://user:password@host:port/database), so Rails and Active Record,
Django, SQLAlchemy, Prisma, pg, and libpq consume it directly. The PG*
variables exist for libraries that prefer separate connection parameters.
Dev and prod are provisioned up front with different roles and passwords, against
the _dev and _prod schemas.
Defaults and limits
Every managed Postgres service ships with the same defaults, there are no self-serve tiers to choose between:
The
--tier flag on floo services add postgres is accepted for backwards-compatibility but ignored, every value maps to the same defaults.
Watching connection usage
floo tracks live Postgres connection usage and warns you before you hit the limit:- Dashboard, the managed-Postgres panel shows
N / 25 connections in useand surfaces a warning when you cross 75%. - CLI,
floo db connections --app my-app [--env dev|prod]prints the same data, with a--jsonmode for agents. - Email, the org owners and admins get an email at 75% sustained, with a one-click
mailto:team@getfloo.comfor capacity requests. One email per app per 24h max.
Vector search with pgvector
Managed Postgres ships with pgvector enabled. Thevector type resolves unqualified, so use it directly with no
CREATE EXTENSION and no schema prefix:
t.vector :embedding, limit: 1536
(or the neighbor gem), Django, pgvector.sqlalchemy, and Prisma all reference
the bare type name. You never need public.vector or a manual extension step.
Schema portability across dev and prod
Each environment gets its own schema,app_<id>_dev and app_<id>_prod, and the
role’s search_path resolves unqualified table names automatically. Migrations
and queries carry no schema prefix and run unchanged in both.
One Rails caveat: config.active_record.schema_format = :sql dumps a
structure.sql that embeds the current schema name and its search_path. Keep
migrations schema-agnostic so a structure dumped against dev loads into prod. The
default :ruby format sidesteps this.
Release promotion without rebuilding runs each service’s migrate_command
before changing any application revision. A migration failure blocks this
promotion. Old code continues serving against the
migrated schema until cutover; if cutover fails, that overlap can continue
indefinitely. There is no fixed overlap window.
Fresh deploys run migrations after deploying the new revisions: with traffic
staging enabled, those revisions receive no traffic until migrations and the
cutover checks pass; without staging, new code can serve before migration runs.
Do not assume the same ordering across deploy paths.
Use expand-then-contract migrations:
- Expand: add nullable columns or new tables while preserving the schema used by the serving code. Keep both old and new code compatible with this schema.
- Backfill: populate the new fields, keeping old and new representations in sync while writes continue; deploy code that can read both during the transition.
- Contract later: remove or rename old fields in a later release, only after backfill is complete and no serving code or intended rollback version depends on them.
Preview database branches
Each preview with managed Postgres gets its own database branch. Migrations and writes there are isolated from dev, prod, and other previews.dev_prod_untouched in --json output.
Preview data modes are empty, seed, and clone-dev. See
Preview environments.
Debug a connection issue
env.managed including the Postgres
handle, that DATABASE_URL and PGHOST appear in floo env list, and that the
app reads env vars rather than a hard-coded local connection string.
Managed services
The shared lifecycle: declare, attach, inspect, remove.
Redis
Cache and queue instances, and how handles map to databases.