# 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
[Section titled “Prerequisites”](#prerequisites)
 - Node.js 18 or later
 - A Flows account with appropriate permissions
 - Basic knowledge of TypeScript/JavaScript

## Installing flowctl
[Section titled “Installing flowctl”](#installing-flowctl)
Install the `flowctl` CLI globally using npm:


*Terminal window*

```
npm install -g @useflows/flowctl
```

Verify the installation:


*Terminal window*

```
flowctl --version
```

## Authentication
[Section titled “Authentication”](#authentication)
Before creating or managing apps, authenticate with Flows:


*Terminal window*

```
flowctl auth login
```

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

To logout:


*Terminal window*

```
flowctl auth logout
```

## Creating Your First App
[Section titled “Creating Your First App”](#creating-your-first-app)
### 1. Create the app
[Section titled “1. Create the app”](#1-create-the-app)
Create a new app in Flows:


*Terminal window*

```
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
[Section titled “2. Create the app code”](#2-create-the-app-code)
Create a TypeScript file (e.g., `main.ts`) that defines your app using the Flows SDK:


**

```
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
[Section titled “3. Create the first version”](#3-create-the-first-version)
Create an initial version of your app:


*Terminal window*

```
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
[Section titled “4. Develop with watch mode”](#4-develop-with-watch-mode)
During development, use watch mode to automatically update your draft version when files change:


*Terminal window*

```
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
[Section titled “5. Publish the version”](#5-publish-the-version)
When your app is ready, publish the draft version to make it available:


*Terminal window*

```
flowctl version publish
```

This makes the version visible and installable in Flows.

## App Structure
[Section titled “App Structure”](#app-structure)
A Flows app consists of several key components:

### App metadata
[Section titled “App metadata”](#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
[Section titled “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
[Section titled “App-level handlers”](#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](../building-apps) section for comprehensive documentation on all app components and services.

## Version Management
[Section titled “Version Management”](#version-management)
### Semantic versioning
[Section titled “Semantic versioning”](#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
[Section titled “Creating new versions”](#creating-new-versions)
Create a new version with an explicit version number:


*Terminal window*

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

Or use interactive SemVer bump selection:


*Terminal window*

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

### Listing versions
[Section titled “Listing versions”](#listing-versions)
View all versions of an app:


*Terminal window*

```
flowctl version list -a <app-id>
```

### Draft workflow
[Section titled “Draft workflow”](#draft-workflow)
When you create a version, it starts as a **draft**:

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

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

## App Scoping
[Section titled “App Scoping”](#app-scoping)
### Project-scoped apps
[Section titled “Project-scoped apps”](#project-scoped-apps)
By default, apps are scoped to a specific project:


*Terminal window*

```
flowctl app create -p my-project-id
```

Project-scoped apps are only visible within that project.

### Organization-wide apps
[Section titled “Organization-wide apps”](#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.