Platform Reference

CI/CD & Deployments

Promote workflow and app configurations between environments, automate deployments from your CI pipeline, manage environment variables, and roll back safely.

FlowOS supports configuration-as-code export and import, an environment promotion API, and pre-built CI/CD pipeline templates for GitHub Actions and GitLab CI. All deployment operations are logged in the audit trail.

Environments

Each workspace can have up to three named environments: development, staging, and production. Environments are independent execution contexts — each has its own connector credentials, secrets vault, and run history.

  • Workflows, apps, and SDK artifacts exist at the workspace level but are deployed to an environment.
  • An artifact can be active in staging but not yet promoted to production.
  • Environment-specific secrets (like production DB credentials) never leave their environment.
  • Each environment has its own API token and base URL subdomain.
Production deployments require a user with the deployer or owner role. If your workspace has deployment approvals enabled, a second user must approve before the deployment goes live.

Promoting Between Environments

Via UI

  1. 1
    Open the artifact — navigate to the workflow, app, or SDK module you want to promote.
  2. 2
    Click Deploy — select the target environment from the dropdown.
  3. 3
    Review the diff — FlowOS shows a structured diff between the current active version and the version being deployed.
  4. 4
    Confirm — for production, you may be prompted for a deployment note and a second approver.
  5. 5
    Monitor — the Deploy Progress panel shows node-by-node activation status. Existing running instances continue on the old version until they complete.

Via Deploy API

POST
/api/v1/deployments

Trigger a deployment programmatically.

json
// Request body
{
  "artifact_type": "workflow",       // workflow | app | sdk_module | sdk_pack
  "artifact_id": "wf_01HX...",
  "version": 7,                      // null = deploy latest draft
  "target_environment": "production",
  "deployment_note": "Adds SLA breach escalation to on-call",
  "notify_on_complete": ["usr_01HX..."]
}

// Response 202 Accepted
{
  "deployment_id": "dep_01HX...",
  "status": "queued",
  "created_at": "2026-06-01T10:00:00Z"
}
GET
/api/v1/deployments/:id

Poll deployment status.

POST
/api/v1/deployments/:id/approve

Approve a deployment pending approval.

POST
/api/v1/deployments/:id/reject

Reject a deployment.

POST
/api/v1/deployments/:id/rollback

Roll back to the previous active version.

Configuration as Code

Export any workflow, app, or SDK artifact as a portable YAML bundle. Bundles include all node definitions, connector bindings (by slug, not credentials), and metadata.

GET
/api/v1/export/workflow/:id

Export a workflow definition as YAML.

POST
/api/v1/import/workflow

Import a workflow from a YAML bundle.

workflow-export.yaml
apiVersion: flowos/v1
kind: Workflow
metadata:
  name: Incident Auto-Escalation
  slug: incident-auto-escalation
  description: Escalates P1 incidents to on-call if unacknowledged after 15 min
  version: 7
  tags: [itsm, escalation, p1]

trigger:
  type: record_event
  config:
    table: incidents
    events: [created, updated]
    conditions:
      - field: severity
        op: eq
        value: P1

nodes:
  - id: wait-15m
    type: Wait
    config:
      duration: 15
      unit: minutes

  - id: check-ack
    type: Condition
    config:
      expression: "{{tables.incidents.status}} !== 'investigating'"

  - id: page-oncall
    type: Notify
    config:
      channel: pagerduty
      connector: pagerduty-prod
      template: p1-escalation
      variables:
        incidentId: "{{trigger.record.id}}"

edges:
  - from: wait-15m
    to: check-ack
  - from: check-ack
    to: page-oncall
    condition: "true"

GitHub Actions Pipeline

.github/workflows/flowos-deploy.yml
name: Deploy FlowOS Workflows

on:
  push:
    branches: [main]
    paths: ['workflows/**']

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install FlowOS CLI
        run: npm install -g @flowos/cli

      - name: Authenticate
        run: flowos auth login --token ${{ secrets.FLOWOS_API_TOKEN }}
        env:
          FLOWOS_WORKSPACE: ${{ secrets.FLOWOS_WORKSPACE_SLUG }}

      - name: Lint workflows
        run: flowos validate workflows/

      - name: Deploy to staging
        run: flowos deploy workflows/ --env staging --wait

      - name: Run smoke tests
        run: flowos test run --env staging --suite smoke

      - name: Promote to production
        if: github.ref == 'refs/heads/main'
        run: flowos deploy workflows/ --env production --wait --note "CD from ${{ github.sha }}"

GitLab CI Pipeline

.gitlab-ci.yml
stages:
  - validate
  - deploy-staging
  - test
  - deploy-production

variables:
  FLOWOS_WORKSPACE: $FLOWOS_WORKSPACE_SLUG

validate:
  stage: validate
  image: node:20
  script:
    - npm install -g @flowos/cli
    - flowos auth login --token $FLOWOS_API_TOKEN
    - flowos validate workflows/

deploy-staging:
  stage: deploy-staging
  script:
    - npm install -g @flowos/cli
    - flowos auth login --token $FLOWOS_API_TOKEN
    - flowos deploy workflows/ --env staging --wait

smoke-tests:
  stage: test
  script:
    - npm install -g @flowos/cli
    - flowos auth login --token $FLOWOS_API_TOKEN
    - flowos test run --env staging --suite smoke

deploy-production:
  stage: deploy-production
  only:
    - main
  script:
    - npm install -g @flowos/cli
    - flowos auth login --token $FLOWOS_API_TOKEN
    - flowos deploy workflows/ --env production --wait
  when: manual   # require human approval in GitLab

CLI Reference

bash
# Authenticate
flowos auth login --token <token>
flowos auth status

# Validate (lint) all YAML files in a directory
flowos validate <path>

# Deploy a directory of YAML files to an environment
flowos deploy <path> --env <development|staging|production> [--wait] [--note "message"]

# Export a single artifact
flowos export workflow <id> --output ./workflows/
flowos export app <id> --output ./apps/

# Import an artifact
flowos import --file ./workflows/incident-auto-escalation.yaml --env staging

# List deployments
flowos deployments list --env production

# Rollback
flowos rollback --deployment <dep_id>

# Run a named test suite in an environment
flowos test run --env staging --suite smoke

Rollback

Every deployment stores the previously active version. Rolling back re-activates the previous version within seconds — no need to re-import or re-deploy the old YAML.

  • Rollback is instant for workflow definitions — running instances on the new version complete normally.
  • App rollbacks restart the preview container on the old bundle.
  • SDK module rollbacks take effect on the next invocation — no in-flight executions are interrupted.
  • A rollback is itself a deployment record and is logged in the audit trail.
Tag your deployments with the Git commit SHA (--note "sha: abc1234") so you can cross-reference deployment history with your git log during incident postmortems.

Database Migrations

Collection-level data migrations live in src/migrations/. Each script is a standalonetsx-executable file that reads MONGODB_URI from the environment, runs a safe transformation, and exits. Migrations are one-way and non-destructive by default — old collections are preserved so you can roll back by reverting the application code.

Available migrations

ScriptWhat it doesRun when
migrate-sys-global-to-workspace.tsCopies records from the old global root_sys_counters and root_sys_notifications collections into per-workspace collections. Preserves max counter sequence values to avoid duplicate ticket numbers.Once, before deploying the workspace-scoped sys_counters fix

Running a migration

bash
# From the flowos-backend root
npx tsx src/migrations/migrate-sys-global-to-workspace.ts

The script connects using MONGODB_URI from .env, logs a count of records found and copied per collection, and exits. It is safe to re-run — counter upserts use $max to never decrease a sequence value, and notification copies skip duplicates.

Writing a new migration

typescript
// src/migrations/my-migration.ts
import mongoose from 'mongoose'
import { config } from 'dotenv'

config()
const MONGO_URI = process.env['MONGODB_URI'] ?? 'mongodb://localhost:27017/flowos'

async function main() {
  await mongoose.connect(MONGO_URI)
  const db = mongoose.connection.db!

  // --- do your work here ---

  console.log('[migration] done')
  await mongoose.disconnect()
}

main().catch(err => { console.error(err); process.exit(1) })
Never delete source collections inside a migration script. Keep the old data until the deployment has been verified in production — rollback is trivially possible while the originals exist.