Skip to Content

The same four nodes in five workflows: pull them into a sub-workflow

write it once
n8n Guide · Part 14

The same four nodes in five workflows: pull them into a sub-workflow

You have copy-pasted the same run of steps into five workflows. One small change now means five edits, and you are never quite sure you got them all. This part shows you how to lift shared logic out into a workflow of its own, call it from everywhere else with one node, and change it in a single place from then on. It is a function call, drawn on a canvas.

3+ copies
The signal that a run of logic should be split out
2 nodes
The whole mechanism: one to call, one to be called
3-4 levels
How deep to let a call chain go, in practice
The five-copy problem

Copy-paste is a loan you repay every time something changes

By now you can read a workflow, branch it with IF and Switch, catch its failures with an Error workflow, and reshape its data with Edit Fields. You also have more and more workflows, and they are starting to look alike.

Then one day you open your own n8n home page and see it. Those four steps for “send a Slack notification” — an IF on severity, a Set for the title, a Slack node to send the message, a row appended to Sheets — are sitting inside five different workflows, identical in all five.

ThenYour boss says every notification from now on has to carry the line “please reply within 24 hours”. That is five places to edit.
ThenThe Slack channel changes from #alerts to #ops-alerts. Five places again.
ThenOne day you forget one of them. A colleague never gets the notification, and you carry the blame.

That is where copy-paste development always ends up. The fix is to pull those four steps out into a small standalone workflow — a sub-workflow — and have the other workflows call it with an Execute Workflow node. From then on, changing the shared logic means changing that one workflow, and every caller picks up the new version automatically.

In plain terms

You wrote the plumber's phone number on five sticky notes and put one in every room. It worked, right up until he changed number. Now you are hunting for sticky notes and hoping there were only five. A sub-workflow is writing it in the address book instead — one entry, one correction, and every room is up to date the moment you close the book.

The rule of thumb: a sub-workflow is a function in workflow form, and the same piece of logic appearing in three or more workflows is the signal to split it out. This is an advanced technique, but the return is enormous — from then on, more than half of your maintenance pain disappears.
Two nodes, two roles

A sub-workflow is not a special kind of workflow

There is no sub-workflow node type and no add-on to install. A sub-workflow is an ordinary workflow, just one designed to be called by others. The whole mechanism rests on two nodes playing two roles.

RoleWhich node to useWhat it does
The caller (parent workflow) Execute Sub-workflow — an action node; older interfaces show it as Execute Workflow Drop it in, pick the workflow to call, hand it items, and wait for the result — or do not wait
The callee (the sub-workflow) Execute Sub-workflow Trigger — a trigger node that starts the workflow; older interfaces show it as Execute Workflow Trigger Catches the items handed in as its input. When the run finishes, the output of the workflow's last node is the return value

Put together, that is a function call with the four familiar moves: the caller passes arguments, the sub-workflow runs on them, the last node's items come back as the return value, and the caller treats that return value as the Execute Workflow node's output and carries on downstream.

sequenceDiagram
  participant U as Node before the call
  participant C as Execute Sub-workflow
  participant T as Execute Sub-workflow Trigger
  participant L as Last node of the sub-workflow
  U->>C: items arrive from upstream
  C->>T: hands those items over as arguments
  T->>L: the sub-workflow runs its own nodes
  L-->>C: the last node's items come back as the return value
  C->>C: that becomes this node's output
One call, one returnNothing is shared between the two workflows except the items going in and the items coming back. That is the whole interface.
If you have ever written a function in any programming language — Python's def, JavaScript's function — a sub-workflow is n8n's version of one. Same input, processing, output; same value in reuse.
When to split, when not

Split too eagerly and you trade one mess for another

Not every piece of logic is worth splitting out. Do it too readily and your workspace fills with fragment workflows, which makes things harder to manage rather than easier. Run the question through this before you reach for a new workflow.

flowchart TD
  A["A run of logic you are
thinking of splitting out"] --> B{"Does the same logic appear
in three or more workflows?"} B -->|"yes"| S["Split it out"] B -->|"no"| C{"Is it ten or more nodes,
messy even to you?"} C -->|"yes"| S C -->|"no"| D{"Does one setting inside it
need managing in one place?"} D -->|"yes"| S D -->|"no"| E{"Does another team or colleague
need to call this logic?"} E -->|"yes"| S E -->|"no"| F["Leave it where it is"]
The split decision in one passFour questions, any one of which is enough on its own. Reaching the last box is a perfectly good outcome.
ScenarioSplit it out?Why
The same logic, three nodes or more, appears in 3+ workflowsSplit itCopy-paste is a maintenance nightmare; split it and one change covers them all
A piece of logic is complicated — ten nodes or more — and even you find it messySplit itIt becomes a black box; the parent is left with the high-level steps and reads cleanly
The logic is used in only one workflowLeave itNothing needs sharing, and the split adds a jump that makes reading harder
Only one or two nodes — a single Slack message, sayLeave itYou save very little and gain another file to maintain
You want one piece of configuration managed in one place, such as a Slack channel nameSplit itWhen the channel is renamed you change the sub-workflow only, and every caller picks up the new value
Another team or a colleague needs to call your logicSplit itA sub-workflow is the interface you hand other people — cleaner than letting them copy your workflow
Before you split, ask whether this logic will need per-caller adjustments later. If every caller ends up wanting its own variant, you are back in copy-paste hell — worse, in fact, because the sub-workflow fills up with IF checks until nobody can read it.
Build the sub-workflow

A shared “send a Slack alert” workflow, built once

Take one concrete case. The logic to split out is: take an event, decide the channel and the color from its severity — error, warn or info — and send it to Slack. After this, any workflow that needs to notify somebody calls this one instead of assembling Slack itself.

flowchart LR
  T["Execute Sub-workflow Trigger
input schema from a JSON example"] --> S{"Switch or IF
on the severity field"} S -->|"error"| E["Slack node
error channel, red"] S -->|"warn"| W["Slack node
warn channel"] S -->|"info"| I["Slack node
info channel"]
Inside the sub-workflowOne entry point, three branches, and no Respond to Webhook anywhere. The last node of whichever branch ran is the return value.
  1. Step 1

    Create the workflow and name it with a prefix

    From the home page, Workflows → + Create workflow. Click the workflow name in the top right and change it to [Sub] Slack Alert. The [Sub] prefix is a convention — the naming section below covers the rest of them — and it tells you at a glance that this workflow exists to be called and never runs on its own.

  2. Step 2

    Use Execute Workflow Trigger as the trigger node

    On the canvas press Tab, or click +, to open the nodes panel. Search for Execute Workflow Trigger in the trigger family and drag it in. Its role is “when somebody calls me, I start here”. Without it, another workflow's Execute Workflow node finds no entry point at all.

  3. Step 3

    Set Input data mode to Define using JSON example

    Open the Execute Sub-workflow Trigger node and find the Input data mode dropdown. There are three options: Define using fields below (type each field name and type by hand), Define using JSON example (paste a sample and n8n infers the schema for you) and Accept all data (no validation — whatever arrives is taken). Choose Define using JSON example and paste this object:

    { "severity": "error", "message": "Database connection failed", "source": "backup-daily" }

    Three keys, and each one earns its place:

    FieldExample valueWhat the sub-workflow does with it
    severity"error"Chooses the branch, and therefore the channel
    message"Database connection failed"The body of the Slack message
    source"backup-daily"Says which workflow raised it, so a reader knows where to look

    The benefit is on the other side: the caller sees this schema hint in its own Execute Sub-workflow node and can assemble its data to match, which saves the back-and-forth over “what am I supposed to send you”. A team that wants the contract written down first picks Define using fields below; a team that would rather take anything and sort it out later picks Accept all data.

  4. Step 4

    Add an IF node to test the severity

    Wire in an IF node with the condition {{ $json.severity }} equals error. The true branch goes to “post in the #ops-error channel with a red icon”. The false branch gets another IF for warn and info — or you can split three ways in one go with a Switch node, which is what Switch is designed for.

  5. Step 5

    One Slack node per branch, with the channel following the severity

    Give each branch its own Slack → Message → Send node. The error branch's Channel is #ops-error, warn takes #ops-warn, and info takes #ops-info. Build the Text field from one shared expression in all three:

    [{{ $json.severity | upper }}] {{ $json.source }}: {{ $json.message }}

    All three channels then get the same-looking message, and you maintain that format in one place.

  6. Step 6

    Let the workflow end on its own

    Let each of the three Slack nodes be the end of its branch. When a sub-workflow finishes, the last node's items are sent back to the caller as the return value automatically. Do not add a Respond to Webhook node — that one belongs to the Webhook node, not to sub-workflows. If you want to return a structure of your own instead, put a Set / Edit Fields node at the end of each branch and build it there, for example { "notified": true, "channel": "#ops-error" }.

  7. Step 7

    Save, and note the workflow ID from the address bar

    Save with Ctrl + S, then look at the browser address bar. It reads something like https://n8n.woowtech.io/workflow/abc123XYZ, and that last segment is the workflow ID. If the caller's Workflow dropdown cannot find this workflow later, you can paste the ID straight in. One thing not to do here: a sub-workflow does not need its Active toggle switched on, because it never runs from a trigger of its own. It waits to be called.

  8. Step 8

    Test it once from the trigger node

    Click Execute step in the top right of the Execute Workflow Trigger node. It does a trial run using the data you pasted into the JSON example as its input. Of the three Slack nodes, only the error branch should fire, because the example's severity is error. A Slack message actually arriving means the sub-workflow itself is sound.

Interface wording moves between versions. Your build may label the trigger node, the input mode dropdown or the run button differently from the words printed here. Recognize the shape — a trigger that only fires when another workflow calls it, a dropdown that decides how strictly the input is described — and go by your own screen and the official docs when they disagree with this page.
Call it from elsewhere

Delete the four nodes, drop in one

The sub-workflow is built. Now open an existing workflow — “back up the database daily”, say — take out the Slack notification nodes stuffed inside it, and replace them with a single Execute Workflow node.

  1. Step 1

    Open the workflow you are reworking

    Say you have a workflow that backs up the database in the small hours: a Schedule Trigger, then the backup, then an IF on the exit code, then a Slack message each for success and failure. It is that last stretch you are about to take apart.

  2. Step 2

    Delete the old Slack nodes and drag in Execute Workflow

    Delete your own IF, Set and Slack nodes entirely. Search the nodes panel for Execute Workflow — the action one, not the trigger version, which is easy to grab by mistake — and wire it in after the IF node.

  3. Step 3

    Set Source to Database and pick the sub-workflow

    Open the node. Source has four modes: Database (pick from the workflows already in the workspace, the usual choice), Local File (read a JSON file from the machine), Parameter (paste the whole workflow JSON into the node) and URL (point at a workflow URL). Keep the default Database and find [Sub] Slack Alert in the dropdown. If it is not there, switch to one of the other modes and point at it by hand.

  4. Step 4

    Decide on Wait for Sub-workflow Completion

    This toggle decides whether the caller waits for the sub-workflow to finish and hand back a return value before carrying on. On means wait; off means carry on the moment the call goes out, which suits a pure notification where you do not care about the result. If you want to keep working with the data the sub-workflow returns, it has to be on. The official docs do not state the default; in practice a newly created Execute Sub-workflow node has it on, so check it yourself if you want to be sure.

  5. Step 5

    Set Mode to Run once with all items

    Mode has two options. Run once with all items hands every upstream item to the sub-workflow at once and the sub-workflow runs a single time. Run once for each item triggers the sub-workflow separately per item, so it runs N times. For a one-at-a-time case like a notification, Run once with all items is fine.

  6. Step 6

    Fill in what you pass, or reshape it first

    If the sub-workflow defined a schema on its trigger — either Define using fields below or Define using JSON example — the Execute Sub-workflow node automatically shows a Workflow Inputs table where you fill in an expression per field, plus an Attempt to convert types toggle that handles type conversion for you. If the sub-workflow is on Accept all data, that block does not appear and the upstream items go in untouched. To change the structure substantially, add a Set / Edit Fields node in front and build the three fields there:

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

    Then save and run it once by hand with Execute Workflow to verify three things in one go: the sub-workflow wakes up, Slack gets the message, and the Execute Workflow node on the caller's side shows the items that came back.

What you get back for the effort: once it calls a sub-workflow, the parent workflow in this example slims from twelve nodes to six nodes plus one Execute Workflow. It reads far more cleanly. And when your boss later says the Slack notification needs an emoji, you change the sub-workflow only and every caller picks it up.

Two ways to pass parameters, and one to avoid by default

How does the Execute Workflow node decide what to hand over? There are three settings worth knowing, and the third one is the one that bites.

ModeHow to set itWhen to use it
Items pass-throughSet Mode to Run once with all items and change nothing else — the upstream items become the sub-workflow's input directlyThe upstream items already have the shape the sub-workflow expects, both {severity, message}, say
Reshape with a Set node firstAdd a Set (or Edit Fields) node in front of Execute Workflow and rewrite the items into the schema the sub-workflow expectsThe upstream data does not match — different field names, missing fields, extra fields. This is the normal case
Run once for each itemSet Mode to Run once for each itemYou genuinely want a separate sub-workflow call per item: 100 notifications means 100 sub-workflow runs
Watch your executions quota with Run once for each item. The sub-workflow is called N times, and the Executions page fills with N sub-workflow execution records. A large loop slows the whole thing down and eats the quota. For a genuinely large batch, batch it first and then hand it over in one go with Run once with all items.
In plain terms

Wait on means phoning the workshop and staying on the line until they tell you the part is in. Wait off means leaving a message and getting on with your day. Both are reasonable. Staying on the line for five minutes when all you wanted was to leave a message is not.

sequenceDiagram
  participant P as Parent workflow
  participant S as Sub-workflow
  Note over P,S: Wait for Sub-workflow Completion, on
  P->>S: call, with items
  S-->>P: returns items when it finishes
  P->>P: downstream nodes run, using what came back
  Note over P,S: Wait for Sub-workflow Completion, off
  P->>S: call, with items
  P->>P: downstream nodes run straight away
  S->>S: finishes on its own, return value goes nowhere
The one toggle that changes the timingOff is faster and the caller cannot use the result. On is slower by exactly however long the sub-workflow takes.
Limits and naming

Six limits, a prefix convention, and a starter toolbox

Splitting logic out feels good. A handful of practical limits are worth knowing now rather than tripping over them six months from now.

ItemWhat actually happensWhat we suggest
Executions are counted separatelyOne caller run is one execution and one sub-workflow run is another. The Executions page lists the two sides separatelyTracing one complete process means cross-referencing both sides; set an Error workflow on both as well
A call chain that runs too deep bogs downA sub-workflow calling a sub-sub-workflow is fine, but many levels get slow and hard to debugIn practice, do not go past 3-4 levels. If it really is that deep, redesign the process or collapse a few levels into one
Version controlChanging a sub-workflow immediately affects every caller. There is no rollback button and no branchBefore you change it, Duplicate workflow and save the copy as [Sub] Slack Alert - backup 20260816, or back it up by exporting the JSON
If the sub-workflow returns nothing, the caller gets nothingIf the last node is an IF and one branch has no node wired after it, a run down that branch leaves the caller with []Every path in the sub-workflow needs a real end node — a Set node producing a result object counts
The Wait option cuts both waysWait for Sub-workflow on means the caller waits; if the sub-workflow takes five minutes, the caller is stuck for those five minutes tooFor pure notifications, where the return value does not matter, turn Wait off so the caller moves on the moment it calls
An error inside the sub-workflow surfaces in the callerA node failing inside the sub-workflow turns the whole Execute Workflow node red, and the caller's workflow fails with itTo have the caller ignore sub-workflow errors, set the Execute Workflow node's On Error to Continue
In plain terms

One errand, two receipts. You paid at the counter and the counter paid the supplier, and the accounts hold both slips separately. Nothing is wrong with that — but when you go looking for what a purchase cost, you have to pull two pieces of paper, and knowing that in advance saves the ten minutes you would spend assuming one of them is missing.

Prefixes, so you can tell them apart at a glance

After a while a workspace holds dozens or hundreds of workflows, half of them parents and half of them called by others. All mixed together, you cannot find anything. Sorting by prefix is the simplest thing that works.

PrefixWhat it meansExample
[Sub]A sub-workflow other workflows call, possibly several of them[Sub] Slack Alert, [Sub] Format Local Date
[Util]Pure utility, always used by a sub-workflow or internally, never exposed[Util] Escape Slack Markdown
[Prod] / [Dev]Keeps the live version and the test version apart when both exist[Prod] Daily Backup, [Dev] Daily Backup
[Cron]A scheduled workflow started by a Schedule Trigger[Cron] Hourly CRM sync
[Webhook]A workflow triggered by an outside system calling in[Webhook] LINE bot reply
No prefixSomething you are still testing by hand, or a draftTest new API

The workflow list page supports search, so typing [Sub] brings up every sub-workflow at once, which makes both editing and taking stock easy. WoowTech's own team has used this convention for a long time, and a new colleague gets it in a second.

Prefixes and tags do different jobs. n8n also has Tags, in the workflow settings, for sorting. They work best together: the prefix says what type of thing this is, the tags say which project or department it belongs to.

A starter toolbox of four

Once the idea has landed, you can build your team a shared toolbox. Here are four sub-workflows plenty of companies actually run, for reference.

Sub-workflowWhat it doesInput schemaOutput
[Sub] Slack AlertSends every Slack notification, routing by severity to a different channel{ severity, message, source }{ notified: true, channel: '...' }
[Sub] Log ExecutionWrites which workflow ran when, whether it succeeded or failed, and how long it took into a shared Google Sheet{ workflow_name, status, duration_ms, note }{ logged: true, row_id: 42 }
[Sub] Format Local DateConverts any date or time to the organization's chosen timezone in the standard YYYY-MM-DD HH:mm:ss format. Configure the IANA timezone for your own location{ raw_date }, ISO or a Unix timestamp{ formatted: '2026-08-16 14:23:00' }
[Sub] Get Employee InfoLooks up the internal HR API by email or employee number and returns the person's name, department and manager{ email } or { employee_id }{ name, department, manager_email }

With those four built, everything else gets cleaner. Need to notify? Do not assemble Slack yourself — call [Sub] Slack Alert. Need a log? Call [Sub] Log Execution. Need to show a time to a person? Call [Sub] Format Local Date and the whole company shows one format. Need to look up a colleague? Call [Sub] Get Employee Info, and when the internal API changes URL you edit exactly one workflow.

Later the HR API address changes, the Slack channel is renamed, the timezone format is adjusted — you edit only the matching sub-workflow, and every workflow in the company picks up the new version automatically. That is what sub-workflows are really worth. The first one costs you time to build and an interface to explain to colleagues — what to send, what comes back — but every extra caller doubles the return on the set again.

When it does not work

Which side is broken, the caller or the callee

Two workflows means two places a fault can live, and the Executions page will not join them up for you. Work out which side you are on first.

flowchart TD
  A["The call did not do
what you expected"] --> B{"Can the Workflow dropdown
even find the sub-workflow?"} B -->|"no"| B1["Check it still exists on the Workflows page,
or point at it by hand with
URL, Local File or Parameter"] B -->|"yes"| C{"Does the run say the
sub-workflow could not be started?"} C -->|"yes"| C1["The first node is not an
Execute Sub-workflow Trigger.
Fix the entry point"] C -->|"no"| D{"Did items actually arrive
at the Execute Workflow node?"} D -->|"no"| D1["Nothing upstream, or the wrong Mode.
The sub-workflow was never called"] D -->|"yes"| E{"Did the sub-workflow
return empty items?"} E -->|"yes"| E1["A branch inside it ends on nothing.
Give every path a real end node"] E -->|"no"| F["Both sides ran. Open the two
executions and compare by time"]
Four questions, in orderEach answer rules out one side. The last box is where you end up when the mechanism is fine and the logic inside the sub-workflow is what needs reading.
SymptomCauseHow to fix it
The Workflow dropdown on the Execute Sub-workflow node cannot find the targetWrong workflow ID, the sub-workflow was deleted, or you are in a different workspaceCheck on the Workflows page that it is still there. Or switch Source from Database to URL, Local File or Parameter and point at it by hand
The run reports Sub-workflow could not be startedThe sub-workflow's trigger node is not an Execute Sub-workflow Trigger — it is a Manual or Schedule trigger, sayGo back to the sub-workflow and make an Execute Sub-workflow Trigger node its first node. That is the entry point sub-workflows use
The caller passed items but the sub-workflow received nothingThe Execute Workflow node's Mode is set wrong — Run once for each item selected, say, but there are no upstream itemsAdd a node upstream to watch whether items really show up, and confirm the Mode. If upstream is empty, the sub-workflow is never called at all
The sub-workflow is extremely slow and the caller is stuck behind itWait for Sub-workflow Completion is on and the sub-workflow itself takes a long time; or the caller used Run once for each item and looped N timesFor a pure notification, turn Wait off. To run things side by side, switch to a batch plus Run once with all items. If it really is slow, go find the bottleneck inside the sub-workflow
The sub-workflow fails and the caller's whole workflow blows up with itThe Execute Workflow node's On Error defaults to Stop Workflow, so an error inside surfaces in the callerIf the caller should carry on regardless — the Slack notification fails but the main process is unaffected — change On Error to Continue
One of the callers broke after you changed the sub-workflowYou touched the input schema it expects — renamed a field, added a required one — and that caller was not updated with itThe Input data mode on the trigger is the interface contract. Take stock of every caller before changing it. For a breaking change, build a separate [Sub] Slack Alert v2 and run both through the transition
Something failed and you cannot tell whether it was the sub-workflow or the callerThe Executions page lists caller and callee as two separate records and does not string them together for youOpen the Execute Sub-workflow node inside the caller's execution — the returned output usually carries the matching sub-execution link or ID — or cross-reference by time on the Executions page. If that leaves you uneasy, set an Error workflow to collect them in one place
The sub-workflow returns something but the caller sees empty itemsA branch off the last node has nothing connected to it — one leg of an IF left dangling, sayMake sure every branch inside has a real end node. If you want a branch to do nothing but still return something, wire in a Set node with { done: true }
In plain terms

The credential question catches people out, so here it is in one line before the questions below. The sub-workflow runs on its own franking machine. Whoever hands it a letter, the stamp on the envelope is the company's, charged to the company's account. Nobody handing over a letter has to know the account number, and nobody can accidentally send one on their own.

Can a sub-workflow call another sub-workflow?
Yes. A sub-workflow can perfectly well hold an Execute Workflow node that calls another one, forming an A → B → C chain. But many levels get slow and hard to debug — every level is its own execution, so the Executions page shows three records and tracing one failure takes three jumps. In practice, keep it within 3-4 levels; past that, redesign, or merge the middle levels.
Do sub-workflows have version control? Can I roll back a bad change?
n8n Community, the self-hosted edition, has no native version control — once you have changed it, it is changed, and there is no undo button. Two things people do in practice. One, the naming convention: Duplicate workflow before you edit and save the copy as [Sub] Slack Alert - backup 20260816. Two, export the JSON into Git: ⋯ → Download at the workflow's top right gets you the JSON, and dropping that into your own Git repo gives you the full version history. n8n Cloud and Enterprise ship workflow history and versioning you can use directly.
What happens when two people edit the same sub-workflow at once?
n8n has no merge and no conflict detection — whoever saves last overwrites whoever saved first. That is also why naming conventions plus tags to divide responsibility matter once a sub-workflow is worth something. Three habits help: agree as a team that every sub-workflow has one owner and ping that owner before touching it; do big changes on your own [Dev] copy first and copy them back to [Prod] once tested; and note that the Enterprise edition has role-based permissions that genuinely separate read-only from writable.
Can I disable a sub-workflow? What happens to the callers?
A sub-workflow has no Active toggle, since it relies on being called and never runs by itself. So “disabling” it means deleting it outright, renaming it, or disabling the Execute Workflow Trigger node — and calls to it then fail: the caller's Execute Workflow node reports that the sub-workflow cannot be found, or errors out. If you have set an Error workflow, it receives that failure and tells you. The way to switch a piece of logic off temporarily without breaking anyone: put an IF node at the start of the sub-workflow that checks a flag, and when the flag is false send it down an empty branch that does nothing. The callers keep working; the sub-workflow effectively does nothing.
Sub-workflow or Code node — when do I use which?
The Code node, which the next part covers, is a few lines of JavaScript inside a single node to work on data. A sub-workflow is a whole stretch of logic across nodes that can be reused in several places. Four ways to decide: if you only need to transform, filter or calculate data, the Code node is faster; if the logic itself involves several node calls, Slack plus Sheets plus a test, use a sub-workflow; if you want non-technical colleagues to be able to read the logic, use a sub-workflow, because it is visual; and if the logic has to be reused across several workflows, either works, but a sub-workflow suits maintenance by non-developers better.
Which credential does a sub-workflow run with — the caller's or its own?
Its own. The callee's credentials are the ones used. So if the Slack node inside [Sub] Slack Alert is bound to the company Slack workspace, it makes no difference who calls it or what account the caller is bound to — the message always goes out through the company workspace. That is a good thing: the sub-workflow is self-contained and the caller does not have to care about its authentication. It is also why enterprise setups often bind a shared set of sub-workflows entirely to a service account, so nothing breaks when someone leaves.
Do sub-workflows have a timeout?
A sub-workflow's run time is inherited from the n8n instance's EXECUTIONS_TIMEOUT environment variable — on Woow n8n the default is usually 3600 seconds, one hour. Past that it is forcibly stopped and the caller sees the execution fail. If the sub-workflow is long-running by nature, fetching data from an outside API for instance, weigh up splitting it into an asynchronous pattern: the caller triggers it, does not Wait, and the sub-workflow logs or notifies on its own once it finishes. That keeps the caller from being stuck.
Can I turn a sub-workflow into a public API for other systems to call?
Not directly. The Execute Workflow Trigger can only be called by other workflows in the same workspace; an outside system cannot reach it. To let outside systems call in, start with a Webhook node instead. The common wrapper pattern: a [Webhook] Slack Alert API workflow uses a Webhook as its entry point, runs an auth check, and then uses Execute Workflow to call the internal [Sub] Slack Alert. The same logic is then reached internally through the sub-workflow and externally through the webhook, over one implementation. Do not paste real keys or a real webhook URL into a workflow you intend to share — strip credentials out before exporting the JSON.
Next

Where to go from here

keep going

You can reuse a whole stretch of logic. Next, a few lines inside one node.

Part 15 covers the Code node: when a handful of JavaScript beats another five nodes on the canvas, and where the line between the two sits in practice.

Open the full guide

Part 14 of the Woow n8n Onboarding Guide series on the Apporo blog.

Adapted from the Woow n8n Onboarding Guide, produced by WoowTech and released under CC BY 4.0. This adaptation is published by Apporo under the same licence.

Light · Air · Water · Control · apporo

in n8n
Reshape the data between two nodes without writing a line of code