第 19 章

Sub-workflow:把常用邏輯抽成小工作流

同一段流程你已經在五個 workflow 都複製貼上過?改一次要改五次、還怕漏掉?這章教你把「共用邏輯」抽成 sub-workflow:一改全改、乾淨到你回頭看以前那些拉麵一樣長的 workflow 會嫌棄自己。

為什麼要學這個

你已經跟著第 7 章認完節點三大類、跟著第 15 章學會 IF/Switch、跟著第 17 章設好 Error workflow、跟著第 18 章把資料整形整乾淨了。你的 workflow 越拉越多、越拉越像。

然後有一天你翻開自己的 n8n 首頁,發現:

  • 「傳 Slack 通知」的那四步驟(IF 判斷 severity → Set 標題 → Slack 發訊息 → Sheets log)—— 在五個 workflow 都在複製貼上
  • 老闆突然說「以後所有通知都要多附一句『請於 24 小時內回覆』」—— 你要改五個地方
  • Slack channel 從 #alerts 改成 #ops-alerts—— 又要改五個地方
  • 某天有一個 workflow 忘記改,同事收不到通知,鍋你揹

這是「複製貼上式開發」必然的下場。解法:把那四步驟抽成一個獨立的小工作流叫 Sub-workflow,其他 workflow 用 Execute Workflow 節點呼叫它。之後改共用邏輯只要改那一個 sub-workflow,所有呼叫方自動吃到新版。

觀念:Sub-workflow 就是「工作流版本的函式(function)」。同一段邏輯在 3+ 個 workflow 都出現,就是抽的訊號。這是進階技巧,但學會的投報率極高——之後所有維護痛點都會少一大半。

什麼是 sub-workflow:兩個角色

Sub-workflow 不是一個特別的節點類型,也不需要任何 add-on。它就是一個普通的 workflow,只是設計成給別人呼叫的。整套機制靠兩個節點分別扮演兩個角色:

角色用哪個節點它在做什麼
呼叫方(Parent workflow) Execute Sub-workflow(Action 類節點;舊版介面顯示為 Execute Workflow) 拉這節點、選要呼叫的 workflow、丟 items 進去、等結果回來(或不等)
被呼叫方(Sub-workflow) Execute Sub-workflow Trigger(Trigger 類節點,當 workflow 開頭;舊版介面顯示為 Execute Workflow Trigger) 接住上面丟進來的 items 當作 input,跑完後 workflow 的最後一個節點的 output 就是回傳值

整個機制長得像程式語言的函式呼叫:

  • 呼叫方傳「參數」(items)給 sub-workflow
  • Sub-workflow 拿參數去執行
  • Sub-workflow 執行完把「回傳值」(最後一個節點的 items)交還給呼叫方
  • 呼叫方把回傳值當作 Execute Workflow 節點的 output,繼續往下游流
提示:如果你有寫過任何程式語言的函式(Python 的 def、JavaScript 的 function),把 sub-workflow 想成 n8n 版的函式就對了。同樣是「輸入 → 處理 → 輸出」,同樣的重用價值。

什麼時候該抽 sub-workflow、什麼時候不用

不是每段邏輯都值得抽。太積極抽反而會讓 workspace 一堆碎片工作流,反過來難管。用下面這張表判斷:

情境該抽嗎?理由
同一段邏輯(3 個以上節點)在 3+ 個 workflow 都出現 該抽 複製貼上維護噩夢,抽出來一改全改
某段邏輯很複雜(10+ 節點),連自己都覺得亂 該抽 抽出來當「黑盒子」,主 workflow 剩下高階步驟,讀起來清爽
邏輯只在一個 workflow 用 不用抽 沒有共用需求,抽出去反而多一次跳轉,讀起來更累
只有一兩個節點(例:一個 Slack 發訊息) 不用抽 抽了也沒省多少,反而多一個檔案要維護
你想「集中管理某段設定」(例:Slack channel 名稱) 該抽 之後 channel 改名只要改 sub-workflow,所有呼叫方跟著吃到新值
要外部團隊/同事來 call 你的邏輯 該抽 Sub-workflow 就是提供給別人的 API 介面,比讓別人抄你的 workflow 乾淨
注意:抽之前先確定這段邏輯「未來不太會為某個特定呼叫方調整」。如果之後每個呼叫方都想要自己的變體,你會回到複製貼上的地獄——甚至更糟,因為 sub-workflow 會塞一堆 if 判斷變得無法讀。

動手:建一個「統一發 Slack 通知」sub-workflow

用一個具體案例走一遍。要抽的邏輯:「收到一個事件,依 severity(error/warn/info)決定 channel 跟顏色,發到 Slack。」 之後任何 workflow 要通知都直接呼叫這一個。

  1. 開一個新 workflow,命名 [Sub] Slack Alert

    首頁 Workflows → + Create workflow。右上角 workflow 名稱點下去改成 [Sub] Slack Alert。前綴 [Sub] 是慣例(後面命名慣例段會講),一眼就知道這個 workflow 是要給別人呼叫的、不會自己主動跑。

  2. Trigger 節點選 Execute Workflow Trigger

    畫布上按 Tab 或點 + 打開節點抽屜,搜尋 Execute Workflow Trigger(在 Trigger 類)拉進來。這個節點的角色就是「當我被別人呼叫時,我從這裡開始」。沒有它,別人的 Execute Workflow 節點會找不到入口。

  3. 設 Input Data Mode = Define using JSON example

    點開 Execute Sub-workflow Trigger 節點,找到 Input data mode 下拉,官方共三個選項:Define using fields below(一欄一欄敲名字+型別)、Define using JSON example(貼一段範例 JSON、n8n 幫你推 schema)、Accept all data(不驗證、來什麼收什麼)。這裡選 Define using JSON example,貼上:

    {
      "severity": "error",
      "message": "資料庫連線失敗",
      "source": "backup-daily"
    }

    好處:呼叫方在他的 Execute Sub-workflow 節點裡會看到這個 schema 提示,直接依樣拼資料傳進來。省掉「我到底要傳什麼」的溝通成本。想要「介面契約先行」的團隊選 Define using fields below;想「先跑再說什麼都收」的選 Accept all data。

  4. 加 IF 節點:判斷 severity

    接一個 IF 節點,條件寫 {{ $json.severity }} equals error。True 分支走「發到 #ops-error 頻道、紅色 icon」;False 分支再接一個 IF 判 warn/info,或者直接用 Switch 節點三分(第 15 章教過 Switch 就是為這種情境設計的)。

  5. Slack 節點:依 severity 決定 channel

    每個分支各拉一個 Slack → Message → Send 節點:error 分支的 Channel 填 #ops-error、warn 填 #ops-warn、info 填 #ops-info。Text 欄位用 expression 統一拼:[{{ $json.severity | upper }}] {{ $json.source }}: {{ $json.message }}。這樣三個 channel 訊息長相一致,維護一次到位。

  6. 結尾:讓 workflow 自然結束(不用 Respond to Webhook)

    三個 Slack 節點各自是分支的終點就好。Sub-workflow 執行完,最後一個節點的 items 會自動被當作回傳值送回呼叫方——不用另外接 Respond to Webhook(那是給 Webhook 節點用的,不是 sub-workflow)。想回傳自訂結構的話,最後可以接一個 Set/Edit Fields 節點整成想要的樣子(例:{ "notified": true, "channel": "#ops-error" })。

  7. Save(Ctrl+S)並複製 workflow ID

    存檔後看瀏覽器網址列,會像 https://n8n.woowtech.io/workflow/abc123XYZ——最後那段就是 workflow ID。等下呼叫方 Execute Workflow 節點下拉找不到時,你可以直接貼這串 ID。注意:sub-workflow 不用把 Active toggle 打開,因為它不是靠自己的 trigger 主動跑,是等別人來呼叫。

  8. 用 Execute Workflow Trigger 節點的「Execute step」按鈕測一次

    點 Execute Workflow Trigger 節點右上角 Execute step,會用你剛剛在 JSON Example 貼的資料當 input 試跑一次。三個 Slack 節點應該只有 error 分支被觸發(因為 example 的 severity 是 error)。真的收到 Slack 訊息就代表 sub-workflow 本身沒問題。

動手:從別的 workflow 呼叫這個 sub-workflow

Sub-workflow 建好了。現在打開一個既有的 workflow(例如「每天備份資料庫」),把原本自己塞在裡面的四個 Slack 通知節點刪掉,改成一個 Execute Workflow 節點呼叫 sub-workflow。

  1. 打開要改造的 workflow

    假設你有一條「每天凌晨備份資料庫」的 workflow,Schedule Trigger → 執行備份 → IF 判斷 exit code → 成功/失敗各發 Slack。現在把「發 Slack」那段拆掉。

  2. 刪掉原本的 Slack 節點群,改拉 Execute Workflow

    把原本自己的 IF/Set/Slack 那些節點刪光。從節點抽屜搜尋 Execute Workflow(Action 類,別跟 Trigger 版搞混了),拉進來接在 IF 節點後面。

  3. Source 選 Database,Workflow 下拉選 [Sub] Slack Alert

    節點打開,Source 有四個模式:Database(從 workspace 現有 workflow 挑,最常用)、Local File(讀本機 JSON 檔)、Parameter(把整段 workflow JSON 貼進節點)、URL(指定 workflow URL)。保留預設 Database,下拉找 [Sub] Slack Alert;找不到再切別的模式手動指定。

  4. 檢查 Wait for Sub-workflow Completion

    這個 toggle 決定「我要等 sub-workflow 跑完拿到回傳值再繼續嗎」。打勾=等;不勾=呼叫完就繼續往下(fire-and-forget,適合純通知不 care 結果)。想用 sub-workflow 的回傳資料繼續處理的話一定要打勾。官方文件沒明說預設值,實務上建 Execute Sub-workflow 節點時是打勾的,不放心請自己確認一次。

  5. Mode 選 Run once with all items

    Mode 有兩個選項:Run once with all items(把上游全部 items 一次丟進 sub-workflow,sub-workflow 跑一次)或 Run once for each item(每筆 item 各觸發一次 sub-workflow,跑 N 次)。通知這種一次一筆的情境選 Run once with all items 就好。

  6. 設要傳的 items:用 Workflow Inputs 或 Set 節點預整形

    Sub-workflow 若在 Trigger 端定義了 schema(Define using fields below 或 Define using JSON example),Execute Sub-workflow 節點會自動顯示 Workflow Inputs 表格讓你逐欄填 expression、還有一個 Attempt to convert types toggle 幫忙做型別轉換。如果 sub-workflow 是 Accept all data,這區塊不會出現,上游 items 原封不動就是 input。想大幅改結構的話,先加一個 Set/Edit Fields 節點整成 { severity, message, source } 再接:

    severity: error
    message: {{ $json.error_message }}
    source: backup-daily

    Save 存檔,手動 Execute Workflow 跑一次驗證:Sub-workflow 那邊會被喚醒、Slack 應該收到訊息、Execute Workflow 節點在呼叫方這邊會顯示回傳的 items。

提示:改成 sub-workflow 呼叫後,主 workflow 從「12 個節點」瘦身到「6 個節點 + 一個 Execute Workflow」。讀起來清爽很多。之後老闆說「Slack 通知要加一個 emoji」,你只改 sub-workflow 就好,所有呼叫方跟著吃到。

傳參數的兩種模式

Execute Workflow 節點怎麼決定要丟什麼給 sub-workflow?主要兩種模式,任選:

模式怎麼設什麼時候用
Items pass-through(直通) Execute Workflow 節點的 Mode 選 Run once with all items,什麼都不動—— 上游 items 直接被當 sub-workflow 的 input 上游 items 的結構已經跟 sub-workflow 期待的一樣(例:都是 {severity, message})
Set 節點預整形 Execute Workflow 前面先加一個 Set(或 Edit Fields),把 items 改成 sub-workflow 期待的 schema 上游來的資料結構跟 sub-workflow 不合(欄位名不同、缺欄位、多欄位),這是常態
Run once for each item Mode 選 Run once for each item 你要對每一筆 item 都單獨呼叫一次 sub-workflow(例:發 100 筆通知就跑 100 次 sub-workflow)
注意:Mode 選 Run once for each item 時,sub-workflow 會被呼叫 N 次、Executions 頁面會出現 N 筆 sub-workflow 執行紀錄。大量迴圈時會拖慢整體、也吃 executions quota。真的要處理大批資料建議先 batch,再一次丟進 sub-workflow 用 Run once with all items。

Sub-workflow 的限制與注意事項

抽出來很爽,但有幾個現實限制要放在心上,不然半年後會踩雷:

項目細節建議做法
Execution 各算各的 呼叫方跑一次是一筆 execution、Sub-workflow 跑一次也是一筆 execution。Executions 頁面兩邊分開列 要追一個完整流程要交叉看兩邊;Error workflow 也建議兩邊都設
呼叫 chain 太深會卡 Sub-workflow 呼叫 sub-sub-workflow 沒問題,但層數多會慢、也難 debug。實務上不要超過 3-4 層 真的很深就重新設計流程,或把幾層合成一層
版本管理 改 sub-workflow 會立刻影響所有呼叫方。沒有回滾按鈕、沒有 branch 改前先 Duplicate workflow 一份存為 [Sub] Slack Alert - backup 20260816,或用 JSON 匯出備份
Sub-workflow 沒回傳的話呼叫方拿到空 Sub-workflow 如果最後一個節點是 IF 且某分支沒接任何節點,那個分支跑完呼叫方會拿到 [] Sub-workflow 每個路徑都要有實際的終點節點(Set 一個結果 object 也行)
Wait 選項的雙面刃 Wait for Sub-workflow 打勾=呼叫方會等;如果 sub-workflow 很慢(例:跑 5 分鐘),呼叫方也會被卡 5 分鐘 純通知類(不 care 回傳)改成不勾 Wait,呼叫完就走,速度快很多
Sub-workflow 出錯的錯誤訊息會冒到呼叫方 Sub-workflow 內某節點失敗,Execute Workflow 節點會整個變紅、呼叫方 workflow 也失敗 想讓呼叫方無視 sub-workflow 錯誤的話,Execute Workflow 節點的 On Error 設 Continue

命名慣例:一眼看出誰是誰

Workspace 用久了會有幾十上百個 workflow,一半是主 workflow、一半是被呼叫的。全部混在一起找不到人。用前綴分類是最簡單有效的做法:

前綴意義範例
[Sub] 被別人呼叫的 sub-workflow(可能有多個呼叫方) [Sub] Slack Alert、[Sub] Format Date TW
[Util] 純工具型,一定被 sub-workflow 或內部使用,不對外 [Util] Escape Slack Markdown
[Prod] / [Dev] 正式版/測試版並存時區隔 [Prod] Daily Backup、[Dev] Daily Backup
[Cron] Schedule Trigger 啟動的排程 workflow [Cron] 每小時同步 CRM
[Webhook] 由外部系統打進來觸發的 workflow [Webhook] Line Bot 回應
沒前綴 一般手動測試中或還在草稿的 測試新 API

Workflow 列表頁支援搜尋,打 [Sub] 就能一次看到所有 sub-workflow,改起來、盤點起來都方便。這個慣例在 Woow 內部團隊沿用很久,新同事看到也一秒理解。

提示:n8n 也有 Tags(workflow 設定裡)可以分類。前綴+Tags 一起用效果最好:前綴管「這是什麼類型」,Tags 管「這屬於哪個專案/哪個部門」。

實例:一組 utility sub-workflow 家族

有了 sub-workflow 觀念以後,你可以幫團隊建一組「共用工具箱」。以下是很多公司實際跑的四個 sub-workflow,供參考:

Sub-workflow 名字做什麼Input schemaOutput
[Sub] Slack Alert 統一發 Slack 通知,依 severity 分流到不同 channel { severity, message, source } { notified: true, channel: '...' }
[Sub] Log Execution 把「哪個 workflow 什麼時候跑了、成功/失敗、多久」寫進共用 Google Sheet { workflow_name, status, duration_ms, note } { logged: true, row_id: 42 }
[Sub] Format Date TW 把任意日期/時間統一轉成台灣時區、標準格式 YYYY-MM-DD HH:mm:ss { raw_date }(ISO 或 Unix timestamp) { formatted: '2026-08-16 14:23:00' }
[Sub] Get Employee Info 用 email 或員工編號查內部 HR API,回員工姓名/部門/主管 { email } 或 { employee_id } { name, department, manager_email }

建完這四個以後,你所有 workflow 都乾淨很多:

  • 要通知?不自己拼 Slack,呼叫 [Sub] Slack Alert
  • 要記 log?不自己拼 Sheets,呼叫 [Sub] Log Execution
  • 要顯示時間給人看?呼叫 [Sub] Format Date TW,全公司格式一致
  • 要查同事?呼叫 [Sub] Get Employee Info,內部 API 換 URL 也只改這一個

之後 HR API 網址換了、Slack channel 改名、時區格式微調——只改對應的那一個 sub-workflow,全公司所有 workflow 自動吃到新版。這就是 sub-workflow 真正的威力。

BNI MCP workflow 呼叫 sub-workflow 的實例
圖 19-1實戰範例:BNI MCP workflow 用 Execute Workflow 節點呼叫子 workflow,把共用邏輯抽出來重用。
觀念:Sub-workflow 就像公司內部的「共用函式庫」。第一次要花時間建、要跟同事講清楚介面(要傳什麼、會回什麼),但一旦建好就是複利。每多一個呼叫方,這組 sub-workflow 的投報率就再翻一倍。

常見卡關與怎麼救

症狀原因怎麼救
Execute Sub-workflow 節點的 Workflow 下拉找不到目標 Workflow ID 錯了、Sub-workflow 被刪了、或你在別的 workspace 先去 Workflows 頁確認 sub-workflow 還在。或把 Source 從 Database 切成 URL/Local File/Parameter 手動指定目標 workflow
執行時報 Sub-workflow could not be started Sub-workflow 的 Trigger 節點不是 Execute Sub-workflow Trigger(是別的 Trigger 例如 Manual、Schedule) 回 sub-workflow 把開頭改成 Execute Sub-workflow Trigger 節點。這是 sub-workflow 專用的入口
呼叫方傳了 items 但 sub-workflow 收到空的 Execute Workflow 節點的 Mode 設錯(例如選 Run once for each item 但上游沒有 items) 在 Execute Workflow 節點上游加一個節點觀察 items 有沒有真的出現;確認 Mode 對;上游是空的話 sub-workflow 也不會被呼叫
Sub-workflow 執行超級慢,呼叫方整個卡 Wait for Sub-workflow Completion 打勾但 sub-workflow 本身要跑很久;或呼叫方用 Run once for each item 迴圈了 N 次 純通知不 care 回傳的話關掉 Wait;要並行的話改用 batch + Run once with all items;真的慢的地方去 sub-workflow 找瓶頸
Sub-workflow 執行失敗,但呼叫方 workflow 也整條爆掉 Execute Workflow 節點的 On Error 預設是 Stop Workflow,sub-workflow 內錯誤會冒到呼叫方 如果 sub-workflow 錯了呼叫方仍要繼續(例:Slack 通知失敗但主流程不受影響),Execute Workflow 節點 On Error 改成 Continue
改了 sub-workflow 之後其中一個呼叫方壞掉 你動到了 sub-workflow 期待的 input schema(改了欄位名、加了必填),但那個呼叫方沒跟著更新 Sub-workflow 的 Execute Sub-workflow Trigger 節點的 Input Data Mode(fields/JSON example)就是介面契約,改介面前要盤點所有呼叫方一起更新;破壞性改動建議另建 [Sub] Slack Alert v2 併行過渡
出錯不知道在 sub-workflow 還是呼叫方 Executions 頁把呼叫方跟被呼叫方兩筆分開列,不會自動串起來 從呼叫方 execution 點進 Execute Sub-workflow 節點,回傳 output 通常帶對應的 sub-execution 連結/ID,或直接到 Executions 頁按時間交叉比對;不放心就設 Error workflow 統一收
Sub-workflow 有回傳但呼叫方看到 items 是空的 Sub-workflow 最後一個節點的分支沒有連接任何東西(例:IF 的其中一支懸空) Sub-workflow 內確認所有分支都有實際的終點節點。想「什麼都不做但要回東西」的話接一個 Set 節點寫 { done: true }

常見問題

Sub-workflow 可以再呼叫另一個 sub-workflow 嗎?可以巢狀嗎?
可以。Sub-workflow 內完全可以再放 Execute Workflow 節點呼叫另一個 sub-workflow,形成 A → B → C 的呼叫鏈。但層數多會慢跟難 debug——每一層都是一筆 execution,Executions 頁面會出現三筆紀錄,出錯要跳三次才追到。實務上建議控制在 3-4 層以內,超過就重新設計,或把中間層合併。
Sub-workflow 有版本管理嗎?改壞可以回滾嗎?
n8n Community(自架版)沒有 native 的版本管理,改了就是改了、沒有 undo 按鈕。實務上兩種做法:(1) 命名慣例——改前 Duplicate workflow 存成 [Sub] Slack Alert - backup 20260816;(2) 匯出 JSON 存 Git——workflow 右上角 ⋯ → Download 拿到 JSON、丟到自家 Git repo,就有完整版本歷史。n8n Cloud 跟 Enterprise 有內建 workflow history/versioning 功能可以直接用。
多人同時改同一個 sub-workflow 會怎樣?
n8n 沒有 merge、沒有 conflict detection——後 save 的人會覆蓋前 save 的人。這也是為什麼 sub-workflow 很值錢時,命名慣例+Tags 分權責很重要。建議做法:(1) 團隊約好每個 sub-workflow 有一個「owner」,其他人動之前先 ping owner;(2) 大改動先在自己的 [Dev] 副本上做,測完再 copy 回 [Prod];(3) Enterprise 版本有 role-based permission 可以真的把「唯讀」跟「可寫」分開。
Sub-workflow 可以 disable 嗎?disable 後呼叫方會發生什麼?
Sub-workflow 沒有 Active toggle(它靠別人來呼叫,不會自己主動跑),所以「disable」的意思是——你可以把它整個刪掉、或改名、或把 Execute Workflow Trigger 節點停用。被呼叫時會失敗,呼叫方的 Execute Workflow 節點會報「找不到 sub-workflow」或執行錯誤。如果你設了 Error workflow,Error workflow 會收到這筆錯誤通知你。「臨時關掉某段邏輯」的做法:在 sub-workflow 開頭加一個 IF 節點檢查 flag、flag 是 false 就走空分支不做事,這樣呼叫方不會壞、但 sub-workflow 實質不動作。
Sub-workflow 跟 Code node(JavaScript)比,什麼時候用哪個?
Code node(下一章會講)是「單一節點裡寫幾行 JS 做資料處理」;Sub-workflow 是「一整段跨節點的邏輯可以在多處重用」。判斷方式:(1) 只是要對資料做轉換/過濾/計算 → Code node 快;(2) 邏輯本身包含多個節點呼叫(Slack + Sheets + 判斷)→ Sub-workflow;(3) 想給非技術同事讀懂邏輯 → Sub-workflow(視覺化);(4) 邏輯要在多個 workflow 重用 → 都可以,但 sub-workflow 比較適合非開發者維護。
Sub-workflow 執行時會用哪個 credential?呼叫方的還是被呼叫方的?
用被呼叫方(sub-workflow)自己設定的 credential。也就是說,如果 [Sub] Slack Alert 裡的 Slack 節點綁的是「Slack 公司 workspace」,不管誰呼叫它、呼叫方綁什麼帳號都不影響——一律用公司 workspace 發訊息。這是好事,代表 sub-workflow 是自足的,呼叫方不用關心它的認證。也是為什麼企業 setup 常見「一組共用 sub-workflow 全部綁 service account」,人員離職不影響。
Sub-workflow 有 timeout 嗎?無限跑會怎樣?
Sub-workflow 執行時間繼承自 n8n instance 的 EXECUTIONS_TIMEOUT 環境變數(Woow n8n 預設通常是 3600 秒 = 1 小時)。超過會被強制中止,呼叫方會看到 execution failed。如果 sub-workflow 本來就會跑很久(例:跑外部 API 抓資料),評估要不要拆成「呼叫方觸發 sub-workflow → 不 Wait → sub-workflow 跑完自己寫 log/通知」的非同步模式,比較不會卡住呼叫方。
可以把 sub-workflow 轉成公開 API 給其他系統打嗎?
Execute Workflow Trigger 本身只能被同 workspace 的其他 workflow 呼叫,外部系統打不到。要讓外部系統打進來要改用 Webhook 節點當開頭。實務上常見「外殼」pattern:一個 [Webhook] Slack Alert API workflow 用 Webhook 當入口、接個 auth 檢查、然後 Execute Workflow 呼叫內部 [Sub] Slack Alert——這樣同一段邏輯內部靠 sub-workflow、外部靠 Webhook,共用同一個實作。