1. MooseStack
  2. Moose Workflows
  3. Define Workflows

Define Workflows

Overview

Workflows automate task sequences with built-in reliability and monitoring. Tasks execute in order, passing data between steps.

Powered by Temporal

Built on Temporal for reliability, retries, and monitoring via GUI dashboard.

Writing Workflow Tasks

Tasks are objects with a run function. Return values automatically pass to the next task.

app/index.ts
import { Task, Workflow } from "@514labs/moose-lib"; export interface Foo {  name: string;} export const task1 = new Task<Foo, void>("task1", {  run: async (ctx) => {    const name = ctx.input.name ?? "world";    const greeting = `hello, ${name}!`;    console.log(greeting);  },}); export const example_workflow = new Workflow("example", {  startingTask: task1,});

Export Task and Workflow objects. Specify startingTask in the Workflow config.

Data Flow Between Tasks

Tasks communicate through their return values. Each task can return an object that is automatically passed as input to the next task in the workflow.

  • Only values inside the object are passed to the next task.
  • The object must be JSON-serializable.
app/index.ts
import { Task, Workflow } from "@514labs/moose-lib"; export interface Foo {  name: string;} export interface Bar {  name: string;  greeting: string;  counter: number;} export const task2 = new Task<Bar, void>("task2", {  run: async (ctx) => {    console.log(`task2 input: ${JSON.stringify(ctx.input)}`);  }}); export const task1 = new Task<Foo, Bar>("task1", {  run: async (ctx) => {    const name = ctx.input.name ?? "world";    const greeting = `hello, ${name}!`;     return {      name: name,      greeting: greeting,      counter: 1    };  },  onComplete: [task2],}); export const examploe_workflow = new Workflow("example", {  startingTask: task1,});

Debugging Workflows

While the Temporal dashboard is a helpful tool for debugging, you can also leverage the Moose CLI to monitor and debug workflows. This is useful if you want to monitor a workflow without having to leave your terminal.

Use the moose workflow status command to monitor a workflow:

moose workflow status example

This will print high level information about the workflow run:

Terminal
Workflow Workflow Status: exampleRun ID: 446eab6e-663d-4913-93fe-f79d6109391fStatus: WORKFLOW_EXECUTION_STATUS_COMPLETED ✅Execution Time: 66s

If you want more detailed information about the workflow's status, including task level logs and inputs/outputs, you can use the --verbose flag:

moose workflow status example --verbose
Terminal
Workflow Workflow Status: exampleRun ID: 446eab6e-663d-4913-93fe-f79d6109391fStatus: WORKFLOW_EXECUTION_STATUS_COMPLETED ✅Execution Time: 66sRequest: GetWorkflowExecutionHistoryRequest { namespace: "default", execution: Some(WorkflowExecution { workflow_id: "example", run_id: "446eab6e-663d-4913-93fe-f79d6109391f" }), maximum_page_size: 0, next_page_token: [], wait_new_event: false, history_event_filter_type: Unspecified, skip_archival: false } Found 17 eventsEvent History:  • [2025-02-21T14:16:56.234808764+00:00] EVENT_TYPE_WORKFLOW_EXECUTION_STARTED  • [2025-02-21T14:16:56.235132389+00:00] EVENT_TYPE_WORKFLOW_TASK_SCHEDULED  • [2025-02-21T14:16:56.259341847+00:00] EVENT_TYPE_WORKFLOW_TASK_STARTED  • [2025-02-21T14:16:56.329856180+00:00] EVENT_TYPE_WORKFLOW_TASK_COMPLETED  • [2025-02-21T14:16:56.329951889+00:00] EVENT_TYPE_ACTIVITY_TASK_SCHEDULED    Activity: example/task1  • [2025-02-21T14:16:56.333761680+00:00] EVENT_TYPE_ACTIVITY_TASK_STARTED  • [2025-02-21T14:16:56.497156055+00:00] EVENT_TYPE_ACTIVITY_TASK_COMPLETED    Result:      {        "counter": 1,        "greeting": "hello, no name!",        "name": "no name",      }

With this more detailed output, you can see the exact sequence of events and the inputs and outputs of each task. This is useful for debugging and understanding the workflow's behavior. The result of each task is included in the output, allowing you to inspect the data that was passed between task for debugging purposes.

If your workflow fails due to some runtime error, you can use the event history timeline to identify the task that failed.

Workflow Lifecycle

Moose compares your code to the last known state and applies changes automatically — both at startup and during hot reload.

Change TypeBehavior
Add workflowRegistered with Temporal (scheduled) or available for manual trigger
Remove workflowTerminated in Temporal
Rename workflowOld terminated, new registered
Workflow configOld terminated, new registered
Task code or configPicked up automatically — the worker restarts and uses the new code
No changesNothing happens — workers reconnect, existing workflows continue

When Moose stops, workflow definitions and schedules persist in Temporal. On restart, Moose reconnects and resumes orchestration.

Workflow config changes that trigger re-registration: schedule, retries, and timeout. Task config & code changes are picked up automatically when the worker restarts.

On this page

OverviewWriting Workflow TasksData Flow Between TasksDebugging WorkflowsWorkflow Lifecycle
FiveonefourFiveonefour
Fiveonefour Docs
MooseStackTemplatesGuides
Release Notes
Source523
  • Overview
Build a New App
  • 5 Minute Quickstart
  • Browse Templates
  • Existing ClickHouse
Add to Existing App
  • Next.js
  • Fastify
Fundamentals
  • Moose Runtime
  • MooseDev MCP
  • Data Modeling
Moose Modules
  • Moose OLAP
  • Moose Streaming
  • Moose Workflows
    • Define Workflows
    • Scheduling
    • Triggers
    • Retries and Timeouts
    • Cancelling Running Workflows
  • Moose APIs & Web Apps
Deployment & Lifecycle
  • Moose Migrate
  • Moose Deploy
Reference
  • API Reference
  • Data Types
  • Table Engines
  • CLI
  • Configuration
  • Observability Metrics
  • Help
  • Release Notes
Contribution
  • Documentation
  • Framework

Tasks are objects with a run function. Return values automatically pass to the next task.

app/index.ts
import { Task, Workflow } from "@514labs/moose-lib"; export interface Foo {  name: string;} export const task1 = new Task<Foo, void>("task1", {  run: async (ctx) => {    const name = ctx.input.name ?? "world";    const greeting = `hello, ${name}!`;    console.log(greeting);  },}); export const example_workflow = new Workflow("example", {  startingTask: task1,});

Export Task and Workflow objects. Specify startingTask in the Workflow config.

app/index.ts
import { Task, Workflow } from "@514labs/moose-lib"; export interface Foo {  name: string;} export interface Bar {  name: string;  greeting: string;  counter: number;} export const task2 = new Task<Bar, void>("task2", {  run: async (ctx) => {    console.log(`task2 input: ${JSON.stringify(ctx.input)}`);  }}); export const task1 = new Task<Foo, Bar>("task1", {  run: async (ctx) => {    const name = ctx.input.name ?? "world";    const greeting = `hello, ${name}!`;     return {      name: name,      greeting: greeting,      counter: 1    };  },  onComplete: [task2],}); export const examploe_workflow = new Workflow("example", {  startingTask: task1,});