> ## Documentation Index
> Fetch the complete documentation index at: https://docs.navisops.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Workflow nodes: actions and logic

> Nodes are the building blocks of every workflow. Action nodes create content or call APIs. Logic nodes branch, delay, or pause for human approval.

Nodes are the building blocks of a workflow. You add them by dragging from the left sidebar onto the canvas, then connect them by dragging from one node's output handle to another node's input handle. Each node has a configuration panel that opens on the right side of the screen when you select it.

Nodes fall into two categories: **action nodes** that do work in your workspace or call external services, and **logic nodes** that control the flow of execution.

***

## Action nodes

Action nodes create, update, or send things. They run in the order you connect them and each one can pass data to nodes further down the chain.

### Create task

Creates a new task in your workspace when the workflow reaches this node.

| Field           | Required | Supports variables | Notes                                                     |
| --------------- | -------- | ------------------ | --------------------------------------------------------- |
| Task title      | Yes      | Yes                | Use `{{project.name}}` or `{{trigger.entity_data.title}}` |
| Description     | No       | Yes                | Rich text description for the task                        |
| Priority        | Yes      | No                 | `low`, `medium`, `high`, or `urgent`                      |
| Due date offset | No       | No                 | Number of days from now                                   |

After this node runs, the created task's data is available to downstream nodes via `{{lastTask.id}}`, `{{lastTask.title}}`, and other `{{lastTask.*}}` variables.

**Example configuration:**

* Title: `Set up environment for {{project.name}}`
* Priority: `high`
* Due date offset: `3`

***

### Update task

Modifies an existing task's status or priority. By default it targets the most recently created task in the current run (`{{lastTask.id}}`), but you can point it at any task ID.

| Field          | Required | Supports variables                  |
| -------------- | -------- | ----------------------------------- |
| Target task ID | Yes      | Yes — defaults to `{{lastTask.id}}` |
| Status         | No       | No — choose from dropdown           |
| Priority       | No       | No — choose from dropdown           |

**Status options:** `backlog`, `todo`, `in_progress`, `in_review`, `done`

**Priority options:** `low`, `medium`, `high`, `urgent`

**Example use case:** After an Approval Gate passes, mark a deployment task as `done` and move on.

***

### Create note

Creates a new note in your workspace.

| Field      | Required | Supports variables |
| ---------- | -------- | ------------------ |
| Note title | Yes      | Yes                |
| Content    | No       | Yes                |

After this node runs, the note's data is available via `{{lastNote.id}}`, `{{lastNote.title}}`, and other `{{lastNote.*}}` variables.

**Example configuration:**

* Title: `{{project.name}} — Kickoff`
* Content: `Goals, milestones, and team assignments for {{project.name}}.`

***

### Update note

Updates the content of an existing note. Useful for appending information to a running log note or updating a document after upstream steps complete.

***

### Create calendar event

Creates a new calendar event in your workspace. Use this to schedule follow-up meetings, deadlines, or review sessions automatically as part of a workflow.

***

### Duplicate entity

Creates a copy of an existing project, task, or note. Useful for templating — keep a master template item and duplicate it each time a workflow fires.

***

### For each

Iterates over a list and runs the connected downstream nodes once for each item in the list. Use this to process a collection of items returned by a previous step, such as a list of tasks from an API response.

***

### Send email

Sends a transactional email to a specified address. This node uses Navis Ops's built-in email sending infrastructure.

| Field      | Required | Supports variables |
| ---------- | -------- | ------------------ |
| To address | Yes      | Yes                |
| Subject    | Yes      | Yes                |
| Body       | Yes      | Yes                |

***

### Send Slack message

Posts a message to a Slack channel via a Slack incoming webhook URL.

| Field        | Required | Supports variables |
| ------------ | -------- | ------------------ |
| Webhook URL  | Yes      | No                 |
| Message text | Yes      | Yes                |

**Example message:** `Task completed: {{trigger.entity_data.title}}`

***

### Send Discord message

Posts a message to a Discord channel via a Discord webhook URL.

| Field        | Required | Supports variables |
| ------------ | -------- | ------------------ |
| Webhook URL  | Yes      | No                 |
| Message text | Yes      | Yes                |

***

### HTTP request

Makes an outbound HTTP request to any external API or webhook endpoint. This is the most flexible action node — use it to call Slack, GitHub, Stripe, your own backend, or any service that accepts HTTP.

| Field   | Required | Supports variables | Notes                                                   |
| ------- | -------- | ------------------ | ------------------------------------------------------- |
| Method  | Yes      | No                 | `GET`, `POST`, `PUT`, `DELETE`                          |
| URL     | Yes      | No                 | The full endpoint URL                                   |
| Headers | No       | No                 | JSON object — e.g., `{"Authorization": "Bearer TOKEN"}` |
| Body    | No       | Yes                | JSON body (not used for GET requests)                   |

Requests time out after 10 seconds. After this node runs, the response is available via `{{lastHttpResponse.data}}`, `{{lastHttpResponse.status}}`, and other `{{lastHttpResponse.*}}` variables.

<Tabs>
  <Tab title="Post to Slack">
    ```json theme={null}
    Method: POST
    URL: https://hooks.slack.com/services/YOUR/WEBHOOK/URL
    Body:
    {
      "text": "Task completed: {{trigger.entity_data.title}}"
    }
    ```
  </Tab>

  <Tab title="Trigger a CI/CD pipeline">
    ```json theme={null}
    Method: POST
    URL: https://api.example.com/ci/run
    Headers: {"Authorization": "Bearer YOUR_TOKEN"}
    Body:
    {
      "branch": "main",
      "environment": "staging"
    }
    ```
  </Tab>

  <Tab title="Read from an API (GET)">
    ```text theme={null}
    Method: GET
    URL: https://api.example.com/projects/{{project.id}}
    Headers: {"Authorization": "Bearer YOUR_TOKEN"}
    ```
  </Tab>
</Tabs>

***

## Logic nodes

Logic nodes don't create or send anything — they control how execution flows through your workflow.

### Condition

Evaluates a true/false expression and branches the workflow into two paths. The Condition node has two output handles: **True** (top) and **False** (bottom). Edges leaving a Condition node are automatically labeled so you can see which path is which on the canvas.

| Field    | Description               | Example                              |
| -------- | ------------------------- | ------------------------------------ |
| Field    | The data path to evaluate | `trigger.entity_data.status`         |
| Operator | How to compare the value  | `equals`, `contains`, `greater than` |
| Value    | What to compare against   | `blocked`, `high`, `client`          |

**Available operators:**

| Operator       | Meaning                                   |
| -------------- | ----------------------------------------- |
| `equals`       | Exact match                               |
| `not_equals`   | Does not match exactly                    |
| `contains`     | Substring is present                      |
| `not_contains` | Substring is not present                  |
| `starts_with`  | Value starts with the string              |
| `ends_with`    | Value ends with the string                |
| `gt`           | Greater than (numeric)                    |
| `gte`          | Greater than or equal to (numeric)        |
| `lt`           | Less than (numeric)                       |
| `lte`          | Less than or equal to (numeric)           |
| `is_empty`     | Value is null, undefined, or empty string |
| `is_not_empty` | Value has any content                     |

**Example — route blocked tasks differently:**

* Field: `trigger.entity_data.status`
* Operator: `equals`
* Value: `blocked`
* **True path:** Create an escalation note and urgent follow-up task
* **False path:** Log the status change with a low-priority task

***

### Delay

Pauses the workflow for a specified amount of time before the next node runs.

| Field    | Description                            |
| -------- | -------------------------------------- |
| Duration | A number representing how long to wait |
| Unit     | `seconds`, `minutes`, or `hours`       |

The maximum delay per node is **30 seconds**. For longer waits, chain multiple Delay nodes in sequence, or redesign using a Scheduled trigger.

<Note>
  Long-running delays use a checkpoint-and-resume mechanism so they don't block other workflows from running. The workflow pauses cleanly and picks up where it left off when the delay expires.
</Note>

**Example use case:** After creating a follow-up task, wait 30 seconds before sending a notification — giving the system time to process the task before the notification references it.

***

### Approval gate

Pauses the workflow entirely and waits for a human to review and approve before execution continues. No subsequent nodes run until someone clicks **Approve & Resume** in the Runs panel.

| Field        | Description                                              |
| ------------ | -------------------------------------------------------- |
| Gate label   | A short name for this checkpoint — e.g., `Lead Approval` |
| Instructions | What the reviewer should check before approving          |

**How the approval gate works:**

<Steps>
  <Step title="Workflow pauses">
    When execution reaches the Approval Gate node, the workflow stops immediately. The run's status changes to **Paused** in the Runs panel.
  </Step>

  <Step title="Reviewer is notified">
    The Runs panel shows an amber pause icon next to the paused run, with the gate's label and instructions visible when expanded.
  </Step>

  <Step title="Reviewer approves">
    The reviewer opens the **Runs** panel, expands the paused run, reads the instructions, and clicks **Approve & Resume**.
  </Step>

  <Step title="Workflow continues">
    Execution resumes from the Approval Gate and runs all remaining downstream nodes.
  </Step>
</Steps>

**Example — gated deployment:**

* Gate label: `Lead Approval`
* Instructions: `Review CI results and staging environment before approving production deploy.`

<Tip>
  Use the Approval Gate for any process that requires a human judgment call — content review before publishing, project sign-off before going active, or deployment review before releasing to production.
</Tip>

***

## Connecting nodes

Hover over any node on the canvas to reveal small circular **handles** on the top (input) and bottom (output) edges. To create a connection:

1. Click and drag from an **output handle** on one node.
2. Drag to an **input handle** on another node.
3. Release — an animated arrow line appears showing the direction of execution.

You can connect one node's output to multiple downstream nodes to branch execution, or connect multiple nodes into a single downstream node to merge paths. Only Condition nodes route execution to exactly one of two branches — all other nodes pass execution to every connected downstream node.

To delete a connection, hover over the line until an **X** appears at the midpoint and click it. To add a label to a connection, double-click it and type.

## Configuration panel

Select any node to open its configuration panel on the right side of the canvas. This is where you set all the node's fields, choose dropdown values, and insert variables using the `{{` picker. Changes save automatically as part of the workflow's auto-save.

## Next steps

<CardGroup cols={2}>
  <Card title="Variables" icon="brackets-curly" href="/guides/workflows/variables">
    Use dynamic data from triggers and previous nodes in your node fields.
  </Card>

  <Card title="Templates" icon="wand-magic-sparkles" href="/guides/workflows/templates">
    See pre-built workflows that combine these nodes into complete automations.
  </Card>
</CardGroup>
