Skip to content

Managing workflows with the Novu API

Update workflow definitions in Development with the Novu API, then publish them to other environments through CI/CD.

Use the Novu API to keep workflow definitions aligned with your codebase and promote them across environments. The sections below explain the production flow first, then show how to implement each phase.

Workflows are scoped to the environment. The same workflowId in Development and Production refers to two separate workflow records. Update definitions in Development, then sync when you are ready to publish. For more on environments, refer to Publishable assets.

How workflow management works in production

Managing workflows in production is a two-phase process. You update workflow definitions in Development from your application code, then you publish those definitions to Staging and Production through CI/CD.

In a real application you usually manage many workflows (for example, payout-initiated, weekly-digest, and order-shipped). The flow is the same for each one: pick a stable workflowId per workflow, run the update-first helper for every ID in your list, then sync each ID in CI/CD.

Phase 1: Update workflow definitions in Development

Store workflow definitions in your repository (steps, payload schema, and channel content). For each workflowId, call update first, because that is the path you use on almost every run. Create only when update returns 404 (that workflow does not exist yet in Development).

Phase 2: Publish workflows to other environments in CI/CD

When definitions in Development are correct, publish them with Sync a workflow. Run sync from your CI/CD pipeline (for example, after a merge to main) once per workflowId so Staging and Production receive the same set of workflows. Use your Development secret key when calling sync. Pass the target environment identifier from the Novu Dashboard. Each sync copies one workflow from Development into the target environment under the same workflowId.

End-to-end sequence

  1. Update workflow definitions in Development for each workflowId you manage as code.
  2. Publish each workflow from Development to the target environment (Staging first, then Production, if you use both).

Prerequisites

Install the SDK for your stack and set your secret key from the Novu Dashboard:

npm install @novu/api zod

Update workflow definitions in Development

This section implements phase 1: updating workflow definitions in Development.

For each workflowId, try update first and create on 404:

  1. Update the workflow with that workflowId and its full definition.
  2. If update returns 404, create a new workflow with the same workflowId.

Keep a list of every workflowId you manage as code (a constant array, a registry map, or exports from workflow modules) and loop over it in your deploy script or bootstrap job.

import { Novu } from "@novu/api";
 
const novu = new Novu({
  secretKey: process.env.NOVU_SECRET_KEY!,
});
 
/** Every workflowId you manage as code. */
const MANAGED_WORKFLOW_IDS = [
  "payout-initiated",
  "weekly-digest",
  "order-shipped",
] as const;
 
/** Build the definition for one workflowId from your in-repo registry. */
function buildWorkflowDefinition(workflowId: string) {
  // Example: return workflowDefinitions[workflowId];
  return {
    name: "Payout Initiated",
    description: "This workflow is used to initiate a payout",
    tags: ["payout"],
    preferences: { /* ... */ },
    origin: "external" as const,
    validatePayload: false,
    payloadSchema: { /* ... */ },
    steps: [ /* ... */ ],
  };
}
 
export async function createOrUpdateWorkflowInDevelopment(workflowId: string) {
  const definition = buildWorkflowDefinition(workflowId);
 
  try {
    return await novu.workflows.update(definition, workflowId);
  } catch (error: unknown) {
    const statusCode =
      error && typeof error === "object" && "statusCode" in error
        ? (error as { statusCode: number }).statusCode
        : undefined;
 
    if (statusCode === 404) {
      return await novu.workflows.create({
        ...definition,
        workflowId,
      });
    }
 
    throw error;
  }
}
 
export async function createOrUpdateAllWorkflowsInDevelopment() {
  for (const workflowId of MANAGED_WORKFLOW_IDS) {
    await createOrUpdateWorkflowInDevelopment(workflowId);
  }
}

For create and update field definitions, refer to Create a workflow and Update a workflow.

Publish workflows with CI/CD

This section implements phase 2: publishing workflows from Development to other environments in CI/CD.

After phase 1 has run for every managed workflowId and Development matches your repository, call Sync a workflow from CI/CD once per ID. Use your Development secret key and the target environment identifier from the Novu Dashboard. Each workflow is copied under the same workflowId in the target environment.

Run sync after workflow definition changes land in your repository (for example, on merge to main). Production and other live environments are updated by syncing from Development, not by editing workflows directly in those environments.

Store these in your CI provider as secrets: NOVU_SECRET_KEY (Development) and NOVU_TARGET_ENVIRONMENT_ID (from the Novu Dashboard).

This job calls Sync a workflow (PUT /v2/workflows/{workflowId}/sync) once per workflowId after phase 1 has updated Development.

name: Publish Novu workflows
 
on:
  push:
    branches:
      - main
 
jobs:
  sync-workflows:
    runs-on: ubuntu-latest
    steps:
      - name: Sync workflows to target environment
        env:
          # Development secret key — workflows are copied FROM Development
          NOVU_SECRET_KEY: ${{ secrets.NOVU_SECRET_KEY }}
          NOVU_TARGET_ENVIRONMENT_ID: ${{ secrets.NOVU_TARGET_ENVIRONMENT_ID }}
        run: |
          MANAGED_WORKFLOW_IDS=(
            payout-initiated
            weekly-digest
            order-shipped
          )
 
          for WORKFLOW_ID in "${MANAGED_WORKFLOW_IDS[@]}"; do
            echo "Syncing ${WORKFLOW_ID}..."
            curl -sf -X PUT "https://api.novu.co/v2/workflows/${WORKFLOW_ID}/sync" \
              -H "Authorization: ApiKey ${NOVU_SECRET_KEY}" \
              -H "Content-Type: application/json" \
              -d "{\"targetEnvironmentId\": \"${NOVU_TARGET_ENVIRONMENT_ID}\"}"
          done

For sync request details, refer to Sync a workflow.

Next steps

For individual workflow operations, refer to these guides:

On this page

Edit this page on GitHub