Skip to content

Custom Apps

Custom apps allow you to extend Flows with your own functionality by writing TypeScript/JavaScript code that implements the Flows app SDK. This guide covers how to create, develop, and deploy custom apps using flowctl, the official CLI tool for Flows app development.

Prerequisitesยป

  • Node.js 18 or later
  • A Flows account with appropriate permissions
  • Basic knowledge of TypeScript/JavaScript

Installing flowctlยป

Install the flowctl CLI globally using npm:

1
npm install -g @useflows/flowctl

Verify the installation:

1
flowctl --version

Authenticationยป

Before creating or managing apps, authenticate with Flows:

1
flowctl auth login

This will open your browser to complete the authentication flow. Once authenticated, you can manage apps and versions.

To logout:

1
flowctl auth logout

Creating Your First Appยป

1. Create the appยป

Create a new app in Flows:

1
flowctl app create

This command will prompt you for:

  • App name: Display name for your app
  • Description: Brief description of what your app does
  • Block color: Color theme for your app's blocks (e.g., #3B82F6)
  • Icon URL: Optional URL to an icon for your app
  • Project ID: Optional project to associate the app with (use -p flag to specify)

The command creates the app and returns an app ID that you'll use for version management.

2. Create the app codeยป

Create a TypeScript file (e.g., main.ts) that defines your app using the Flows SDK:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import { defineApp, events } from "@slflows/sdk/v1";

export default defineApp({
  name: "Hello World App",

  config: {
    message: {
      name: "Greeting Message",
      type: "string",
      required: true,
      default: "Hello, World!",
    },
  },

  blocks: {
    greeter: {
      name: "Greeter",
      description: "Emits a greeting message",

      outputs: {
        default: {
          name: "Greeting",
          description: "The greeting message",
          type: "string",
        },
      },

      schedules: {
        greet: {
          description: "Send greeting every hour",
          definition: {
            type: "frequency",
            frequency: {
              interval: 1,
              unit: "hours",
            },
          },
          onTrigger: async (input) => {
            await events.emit({
              message: input.app.config.message,
              timestamp: new Date().toISOString(),
            });
          },
        },
      },
    },
  },
});

3. Create the first versionยป

Create an initial version of your app:

1
flowctl version create -e main.ts

Options:

  • -e, --entrypoint: Path to your app's entry file (required)
  • -a, --app: App ID (if not specified, will prompt or use the most recent)
  • -v, --version: Version number (if not specified, will prompt for SemVer bump)
  • --ui-entrypoint: Optional path to UI entry file for custom interfaces

The version is created in draft state, which means it's not yet visible to users.

4. Develop with watch modeยป

During development, use watch mode to automatically update your draft version when files change:

1
flowctl version update -e main.ts --watch

This monitors your files and automatically uploads changes to the draft version, enabling rapid iteration.

5. Publish the versionยป

When your app is ready, publish the draft version to make it available:

1
flowctl version publish

This makes the version visible and installable in Flows.

App Structureยป

A Flows app consists of several key components:

App metadataยป

  • name: Display name shown in the UI
  • installationInstructions: Markdown text shown during installation
  • config: Configuration fields set during installation
  • signals: Values exposed by the app to blocks

Blocksยป

Blocks are the entities users place on the canvas. Each block can have:

  • Inputs: Receive events from other blocks
  • Outputs: Emit events to other blocks
  • Config: Block-specific configuration fields
  • Lifecycle: onSync and onDrain handlers for state management
  • HTTP: Handle incoming HTTP requests
  • Schedules: Periodic or cron-based triggers
  • Timers: Handle one-time delayed execution

App-level handlersยป

  • onSync: Called when the app needs to synchronize (e.g., provision resources)
  • onDrain: Called when the app is being removed (cleanup)
  • onInternalMessage: Receive messages from blocks
  • onTimer: Handle app-level timers
  • http.onRequest: Handle app-level HTTP requests

See the Building Apps section for comprehensive documentation on all app components and services.

Version Managementยป

Semantic versioningยป

Flows apps use semantic versioning (SemVer): MAJOR.MINOR.PATCH

  • MAJOR: Breaking changes
  • MINOR: New features, backwards compatible
  • PATCH: Bug fixes, backwards compatible

Creating new versionsยป

Create a new version with an explicit version number:

1
flowctl version create -e main.ts -v 1.2.0

Or use interactive SemVer bump selection:

1
2
flowctl version create -e main.ts
# Will prompt: major, minor, or patch?

Listing versionsยป

View all versions of an app:

1
flowctl version list -a <app-id>

Draft workflowยป

When you create a version, it starts as a draft:

  1. Create: flowctl version create - Creates a draft version
  2. Develop: flowctl version update --watch - Iterate on the draft
  3. Publish: flowctl version publish - Make it available to users

Draft versions are only visible to developers and are not installable by users.

App Scopingยป

Project-scoped appsยป

By default, apps are scoped to a specific project:

1
flowctl app create -p my-project-id

Project-scoped apps are only visible within that project.

Organization-wide appsยป

To make an app available across your entire organization, create it without specifying a project, or contact your Flows administrator to promote an existing project-scoped app to organization-wide visibility.

Publishing strategy

A common workflow is to develop and test apps in a development project, then promote them organization-wide once stable.