floo services is the canonical surface for managed services (Postgres, Redis, Storage) and the place to inspect any service — managed or application — running in your app.
Managed services hold persistent state, so floo makes destruction explicit: removing a managed service is always a floo services remove command, never a side effect of editing config. You can provision with floo services add here, or declaratively with [managed.<name>] blocks — either way a deploy creates what’s declared-but-missing and never destroys. Every floo services mutation updates an auto-generated .floo/services.lock file that’s committed to your repo as a record of stateful changes.
The legacy
[postgres], [redis], [storage] sections in floo.app.toml still auto-provision on first deploy during the deprecation window, and emit a warning telling you to run floo services migrate. Once migrated, those sections can be removed. See Managed Services for the full transition story.list
List all services for an app — both application services (web, api, worker) and managed services (postgres, redis, storage).
Flags
| Flag | Description | Default |
|---|---|---|
--app APP | App name or UUID | inferred from config |
--env ENV | Environment to query: dev or prod | dev |
JSON output
show
Show details for one service. Branches automatically: managed services return tier and status; application services return port, URL, and ingress. You don’t need to know which type a name maps to.Flags
| Flag | Description |
|---|---|
--app APP | App name or UUID |
show in plaintext. Read DATABASE_URL / REDIS_URL / STORAGE_BUCKET via floo env get when you need the value.
add
Provision a new managed service. Idempotent on(app, type, name) — running the same command twice returns the existing row, not an error.
Arguments
| Argument | Description |
|---|---|
<type> | Service type: postgres, redis, or storage. |
Flags
| Flag | Description | Default |
|---|---|---|
--app APP | App name or UUID | inferred from config |
--tier TIER | Deprecated. Accepted for backwards-compatibility but ignored — every managed Postgres service now ships with the same defaults (25 connections, 60s statement timeout, 128 MB work_mem). For sustained higher concurrency, email team@getfloo.com for a dedicated instance. | default |
--name NAME | Logical name for this service row (lowercase, alphanumeric + underscores). Useful when you want more than one of the same type. | default |
What it does
- Calls
POST /v1/apps/{app_id}/managed-servicesto provision the underlying resource (Postgres schema + role on the shared instance, Upstash Redis database, or GCS bucket). - Synthesizes the corresponding env var(s) — Postgres gets
DATABASE_URL+PG*, Redis getsREDIS_URL, Storage getsSTORAGE_BUCKET+STORAGE_URL— and injects them into your app’s environment scope. - Updates
.floo/services.lockatomically. Commit the lock file alongside your other changes.
[services.<name>.env] managed = [...]. Run floo preflight --json to see the exact env_injection_plan.
For Postgres, both dev and prod credentials are provisioned up front. Promote does not need to re-provision.
remove
Permanently destroy a managed service and its data. This is a tier-3 destructive operation: it drops the Postgres schemas / deletes the Redis databases / deletes the GCS buckets for the service.Arguments
| Argument | Description |
|---|---|
<type> | Service type: postgres, redis, or storage. |
Flags
| Flag | Description | Default |
|---|---|---|
--app APP | App name or UUID | inferred from config |
--name NAME | Service row name. | default |
--yes-i-know-this-destroys-data | Skip interactive confirmation. Required in non-interactive contexts. Deliberately verbose because destroying user data must be an explicit decision. | off |
--yes or --force. The flag name is not a bug.
floo services remove is the only path that destroys managed-service data. Deploy never destroys. Removing a [postgres] section from floo.app.toml and pushing leaves the service running and surfaces a to_orphan warning in floo preflight.
migrate
One-shot conversion from the legacy[postgres] / [redis] / [storage] TOML sections to CLI-managed state. Idempotent — running it on an already-migrated app is a no-op. Zero data impact: the underlying managed-service rows already exist; migrate only changes how they’re authored going forward.
Arguments
| Argument | Description | Default |
|---|---|---|
PATH | Project directory containing floo.app.toml | . |
Flags
| Flag | Description |
|---|---|
--app APP | App name or UUID |
What it does
- Reads each
[postgres]/[redis]/[storage]section fromfloo.app.toml. - Calls
floo services addfor each (idempotent — existing rows are recorded, not re-created). - Writes
.floo/services.lock. - Prints instructions to delete the legacy TOML sections so the deprecation warning stops firing on every deploy.
The lock file
Every successfuladd, 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.
floo services command re-syncs it from platform truth.
Errors
| Code | Meaning |
|---|---|
NOT_AUTHENTICATED | Run floo auth login first |
SERVICE_NOT_FOUND | No service with that name exists on the app |
MANAGED_SERVICE_NOT_FOUND | No managed service of that type/name exists (raised by remove) |
MANAGED_SERVICE_ALREADY_EXISTS | Cannot create a duplicate (would never happen via add, which is idempotent — surfaces if you call the API directly with conflicting state) |
INVALID_TIER | Tier value is not basic, standard, or performance |
Related
- Managed Services — full lifecycle: lock file, deprecation, dev/prod isolation per service type.
floo preflight— see which managed services areto_provision,to_retain,to_orphan, or in flight.floo db— query and migrate the managed Postgres database directly.