Skip to main content

Documentation Index

Fetch the complete documentation index at: https://getfloo.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

Managed services are floo’s stateful primitives — Postgres, Redis, and Storage. They hold persistent data, they outlive any single deploy, and destroying them is irreversible. For that reason, floo treats managed services as CLI-canonical: provisioning and removal are explicit floo services commands, never side effects of editing a config file.

Provision a service

Use floo services add for any managed service. The command is idempotent on (app, type, name), so re-running it is safe.
floo services add postgres --app my-app
floo services add redis --app my-app
floo services add storage --app my-app
Each command:
  1. Provisions the underlying resource (a Postgres schema + role on the shared instance, an Upstash Redis database, or a GCS bucket).
  2. Synthesizes the matching env vars and injects them into your app’s environment scope.
  3. Writes .floo/services.lock — commit it alongside other changes.
ServiceType flagEnv vars injected
PostgrespostgresDATABASE_URL, PGHOST, PGPORT, PGDATABASE, PGUSER, PGPASSWORD
RedisredisREDIS_URL
StoragestorageSTORAGE_BUCKET, STORAGE_URL
Connection credentials are never stored in floo.app.toml or .floo/services.lock. They’re synthesized at deploy time and injected directly into the runtime environment. Postgres DATABASE_URL is a standard PostgreSQL URI that mainstream frameworks can parse directly; the PG* vars expose the same default connection as separate fields for tools that prefer them.

Attach Credentials To Services

For single-service apps, managed credentials go to the only runtime service unless top-level [env] managed = [] opts out. For multi-service apps, put the attachment next to the service that needs it:
[services.web]
type = "web"
path = "./web"
port = 3000

[services.web.env]
managed = []

[services.api]
type = "api"
path = "./api"
port = 8000

[services.api.env]
managed = ["postgres", "redis"]
required = ["STRIPE_SECRET_KEY"]
Handles map to generated env vars: postgres gives DATABASE_URL plus PG*, redis gives REDIS_URL, and storage gives STORAGE_BUCKET plus STORAGE_URL. Named services use type:name, such as postgres:analytics for DATABASE_URL_ANALYTICS. If no service declares managed, floo keeps legacy all-service injection. Once any service declares it, services without managed receive no managed-service credentials. floo only strips keys owned by managed-service records, so an external user-managed DATABASE_URL is not swept up by this filter. floo preflight --json shows the exact per-service plan in env_injection_plan.

Inspect

floo services list --app my-app                # everything: managed + application services
floo services info default --app my-app        # one row, with tier and status
floo env get DATABASE_URL --app my-app          # plaintext credential when you actually need it

Remove

floo services remove is the only path that destroys managed-service data. Deploy never destroys, regardless of what’s in floo.app.toml.
# Interactive: type the service name to confirm
floo services remove postgres --app my-app

# Non-interactive: explicit verbose flag — no --yes shortcut
floo services remove postgres --app my-app --yes-i-know-this-destroys-data
The flag name is deliberately verbose. Destroying user data must be an explicit, acknowledged decision — there is no --force.

The lock file

Every add, remove, and migrate updates .floo/services.lock atomically. The file is auto-generated, committed to the repo, and never hand-edited. It’s a record of state, not a source — the platform DB is authoritative. Same model as package-lock.json or Cargo.lock.
{
  "version": 1,
  "managed_services": [
    {
      "type": "postgres",
      "name": "default",
      "tier": "basic",
      "created_at": "2026-04-24T15:00:00Z"
    }
  ]
}
Hand-editing does nothing. Running any floo services command re-syncs the file from platform truth.

Dev and prod isolation

Each service type isolates dev from prod differently. Read this before promoting to prod.
ServiceDev/prod model
PostgresFully isolated. Provisioning creates both {schema}_dev and {schema}_prod schemas, each with its own role and password. Dev gets DATABASE_URL + PG* for _dev; prod gets a different role/password for _prod. Promote does not need to re-provision.
RedisShared. A single Upstash database backs both dev and prod. The dev REDIS_URL is mirrored into prod env vars on first prod deploy. If you write to Redis in dev, prod sees it.
StorageShared. A single GCS bucket backs both dev and prod. The dev STORAGE_BUCKET is mirrored into prod env vars. Uploads from dev are visible in prod.
If your app stores anything in Redis or Storage that must not leak between environments, namespace your keys / object paths in application code (e.g., prefix with dev: / prod: based on a runtime flag).

Preflight reconciliation

floo preflight shows the planner’s view of managed-service state across five bins:
  • to_provision — declared (via CLI or legacy TOML) but no row exists. Will be created on the next deploy or floo services add.
  • to_retain — declared and exists. No-op.
  • to_retry — declared and a failed row exists. The next deploy retries provisioning into the same row.
  • to_orphan — exists, not declared anywhere. Will NOT be deprovisioned. Surfaced as a non-blocking warning telling you to run floo services remove if you actually want destruction.
  • in_flight_deprovisioning — a deprovisioning row is mid-flight. Excluded from to_retain / to_orphan until it completes.
The orphan bin exists because deploy never destroys data. Clearing an orphan is always an explicit remove.

Legacy TOML sections (deprecated)

Earlier versions of floo accepted [postgres], [redis], and [storage] top-level sections in floo.app.toml as a declarative shortcut:
# legacy — still works, but deprecated
[postgres]
tier = "basic"

[redis]

[storage]
These sections still auto-provision on first deploy during the deprecation window, but every deploy that processes them emits a warning:
DEPRECATED: [postgres] in floo.app.toml. Run 'floo services migrate' to move to CLI-managed state.
To migrate an existing app:
floo services migrate --app my-app
migrate is idempotent and has zero data impact — it records the existing managed-service rows in .floo/services.lock and prints instructions to remove the legacy TOML sections. After migration, your authoring surface is the CLI alone; the underlying managed services are untouched. After the sunset date, the parser will ignore the legacy sections entirely. Apps that haven’t migrated keep their managed services (the CLI sees them via floo services list); only the authoring surface changes.

Capacity

Every managed Postgres service ships with the same defaults — there are no self-serve tiers to choose between:
SettingDefault
Max connections25
Statement timeout60s
Idle-in-transaction timeout120s
Lock timeout10s
work_mem128 MB
The --tier flag on floo services add postgres is accepted for backwards-compatibility but ignored — every value maps to the same defaults. Redis uses Upstash. Storage uses GCS buckets. Neither has tier choices.
Need more than 25 connections? Email team@getfloo.com — for sustained higher concurrency we provision dedicated Postgres instances rather than a self-serve performance tier.

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 use and surfaces a warning when you cross 75%.
  • CLIfloo db connections --app my-app [--env dev|prod] prints the same data, with a --json mode for agents.
  • Email — the org owners and admins get an email at 75% sustained, with a one-click mailto:team@getfloo.com for capacity requests. One email per app per 24h max.
Most apps that hit the cap either need connection pooling at the application layer (PgBouncer, SQLAlchemy pool tuning) or more raw capacity. If pooling isn’t enough, email us.

Usage metering

ResourceMetered by
Compute (Cloud Run)per vCPU-second + per GiB-second
Postgresshared instance, metered by compute
Redisserverless (Upstash), metered by commands
Storageper GB stored + per operation
Bandwidthper GB egress
Your plan includes compute credits — 5 lifetime (Free), 5 / month (Hobby), 20 / month (Pro), 200 / month (Team) — and one credit equals $1 of metered app usage. Usage beyond your credits is billed as overage up to your spend cap.

Databases

Code examples and debugging for Postgres and Redis.

Cloud Storage

Upload, download, and signed URL patterns.

Cron Jobs

Schedule recurring tasks inside your app’s containers.