Skip to main content
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).
floo services list --app my-app
floo services list --app my-app --env prod

Flags

FlagDescriptionDefault
--app APPApp name or UUIDinferred from config
--env ENVEnvironment to query: dev or proddev

JSON output

{
  "success": true,
  "data": {
    "services": [
      {
        "name": "web",
        "service_type": "web",
        "port": 3000,
        "status": "live",
        "ingress": "public"
      },
      {
        "name": "default",
        "service_type": "postgres",
        "tier": "basic",
        "status": "ready"
      }
    ]
  }
}

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.
floo services show web --app my-app
floo services show default --app my-app    # the default postgres row

Flags

FlagDescription
--app APPApp name or UUID
Connection credentials are never returned by 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.
floo services add postgres --app my-app
floo services add redis --app my-app
floo services add storage --app my-app

Arguments

ArgumentDescription
<type>Service type: postgres, redis, or storage.

Flags

FlagDescriptionDefault
--app APPApp name or UUIDinferred from config
--tier TIERDeprecated. 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 NAMELogical name for this service row (lowercase, alphanumeric + underscores). Useful when you want more than one of the same type.default

What it does

  1. Calls POST /v1/apps/{app_id}/managed-services to provision the underlying resource (Postgres schema + role on the shared instance, Upstash Redis database, or GCS bucket).
  2. Synthesizes the corresponding env var(s) — Postgres gets DATABASE_URL + PG*, Redis gets REDIS_URL, Storage gets STORAGE_BUCKET + STORAGE_URL — and injects them into your app’s environment scope.
  3. Updates .floo/services.lock atomically. Commit the lock file alongside your other changes.
For multi-service apps, runtime injection is controlled by [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.
# Interactive: type the service name to confirm
floo services remove postgres --app my-app

# Non-interactive (CI, agents): explicit verbose flag
floo services remove postgres --app my-app --yes-i-know-this-destroys-data

Arguments

ArgumentDescription
<type>Service type: postgres, redis, or storage.

Flags

FlagDescriptionDefault
--app APPApp name or UUIDinferred from config
--name NAMEService row name.default
--yes-i-know-this-destroys-dataSkip interactive confirmation. Required in non-interactive contexts. Deliberately verbose because destroying user data must be an explicit decision.off
There is no --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.
floo services migrate --app my-app

Arguments

ArgumentDescriptionDefault
PATHProject directory containing floo.app.toml.

Flags

FlagDescription
--app APPApp name or UUID

What it does

  1. Reads each [postgres] / [redis] / [storage] section from floo.app.toml.
  2. Calls floo services add for each (idempotent — existing rows are recorded, not re-created).
  3. Writes .floo/services.lock.
  4. Prints instructions to delete the legacy TOML sections so the deprecation warning stops firing on every deploy.

The lock file

Every successful 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 the lock file does nothing. Running any floo services command re-syncs it from platform truth.

Errors

CodeMeaning
NOT_AUTHENTICATEDRun floo auth login first
SERVICE_NOT_FOUNDNo service with that name exists on the app
MANAGED_SERVICE_NOT_FOUNDNo managed service of that type/name exists (raised by remove)
MANAGED_SERVICE_ALREADY_EXISTSCannot create a duplicate (would never happen via add, which is idempotent — surfaces if you call the API directly with conflicting state)
INVALID_TIERTier value is not basic, standard, or performance
  • Managed Services — full lifecycle: lock file, deprecation, dev/prod isolation per service type.
  • floo preflight — see which managed services are to_provision, to_retain, to_orphan, or in flight.
  • floo db — query and migrate the managed Postgres database directly.