N8n to comfyui z-image

I am running n8n and ComfyUI locally. In this n8n workflow, everything works, but it is not getting prompts from the local folder. It should take the prompts from C:\Users\Whisp.n8n-files\Images\output_images_prompt\*.txt and send them to ComfyUI Z Image Turbo to process. Then save the images here: C:\Users\Whisp.n8n-files\Images\output_images\. it just generate random asian girl. , Can someone help me fix this? Thank you very much for your help in advance.

this is my workflow json :

{
“name”: “ComfyUI Z-Image Turbo --Work Progress”,
“nodes”: [
{
“parameters”: {},
“id”: “f5a7f177-28c6-4ed7-8fef-59a95e43cc6e”,
“name”: “Manual Trigger”,
“type”: “n8n-nodes-base.manualTrigger”,
“typeVersion”: 1,
“position”: [
0,
0
]
},
{
“parameters”: {
“fileSelector”: “C:\Users\Whisp\.n8n-files\Images\output_images_prompt\*.txt”,
“options”: {}
},
“id”: “1e4099fc-ded4-4ea1-a8a7-73b1d0cf6f45”,
“name”: “Read All Prompt Files”,
“type”: “n8n-nodes-base.readWriteFile”,
“typeVersion”: 1,
“position”: [
192,
0
]
},
{
“parameters”: {
“jsCode”: “const results = ;\n\nfor (const item of $input.all()) {\n const key = Object.keys(item.binary || {})[0];\n\n if (!key) continue;\n\n const text = Buffer.from(item.binary[key].data, ‘base64’)\n .toString(‘utf8’)\n .trim();\n$input.first().json.fileName\n const fileName = (item.binary[key].fileName || ‘output’)\n .replace(‘.txt’, ‘’);\n\n if (!text) continue;\n\n results.push({\n json: {\n prompt: text,\n outputFileName: fileName\n }\n });\n}\n\nreturn results;”
},
“id”: “71be231e-4b2c-462c-be95-5b0fdc44a265”,
“name”: “Parse Prompts”,
“type”: “n8n-nodes-base.code”,
“typeVersion”: 2,
“position”: [
432,
0
]
},
{
“parameters”: {
“jsCode”: “const prompt = $json.prompt;\nconst outputFileName = $json.outputFileName;\n\nconst workflow = {\n “104:85”: {\n “inputs”: {\n “clip_name”: “qwen_3_4b.safetensors”,\n “type”: “lumina2”,\n “device”: “default”\n },\n “class_type”: “CLIPLoader”\n },\n “104:86”: {\n “inputs”: {\n “vae_name”: “ae.safetensors”\n },\n “class_type”: “VAELoader”\n },\n “104:89”: {\n “inputs”: {\n “text”: prompt,\n “unet_name”: “z_image_turbo_bf16.safetensors”,\n “weight_dtype”: “default”\n },\n “class_type”: “UNETLoader”\n },\n \n"104:90”: {\n “inputs”: {\n “text”: prompt,\n “clip”: [“104:85”, 0]\n },\n “class_type”: “CLIPTextEncode”\n},\n “104:87”: {\n “inputs”: {\n “conditioning”: [“104:90”, 0]\n },\n “class_type”: “ConditioningZeroOut”\n },\n “104:91”: {\n “inputs”: {\n “width”: 1024,\n “height”: 1024,\n “batch_size”: 1\n },\n “class_type”: “EmptySD3LatentImage”\n },\n “104:93”: {\n “inputs”: {\n “shift”: 3,\n “model”: [“104:89”, 0]\n },\n “class_type”: “ModelSamplingAuraFlow”\n },\n “104:92”: {\n “inputs”: {\n “seed”: Math.floor(Math.random() * 999999999),\n “steps”: 4,\n “cfg”: 1,\n “sampler_name”: “res_multistep”,\n “scheduler”: “simple”,\n “denoise”: 1,\n “model”: [“104:93”, 0],\n “positive”: [“104:90”, 0],\n “negative”: [“104:87”, 0],\n “latent_image”: [“104:91”, 0]\n },\n “class_type”: “KSampler”\n },\n “104:88”: {\n “inputs”: {\n “samples”: [“104:92”, 0],\n “vae”: [“104:86”, 0]\n },\n “class_type”: “VAEDecode”\n },\n “60”: {\n “inputs”: {\n “filename_prefix”: outputFileName,\n “images”: [“104:88”, 0]\n },\n “class_type”: “SaveImage”\n }\n};\n\nreturn [{\n json: {\n prompt,\n outputFileName,\n comfyPayload: { prompt: workflow }\n }\n}];"
},
“id”: “398c7b35-c623-4bb8-be90-efe0509d7348”,
“name”: “Build ComfyUI Payload”,
“type”: “n8n-nodes-base.code”,
“typeVersion”: 2,
“position”: [
672,
0
]
},
{
“parameters”: {
“method”: “POST”,
“url”: “http://127.0.0.1:8000/prompt”,
“sendBody”: true,
“bodyParameters”: {
“parameters”: [
{
“name”: “prompt”,
“value”: “={{ $json.comfyPayload.prompt }}”
}
]
},
“options”: {
“timeout”: 30000
}
},
“id”: “5a2ec990-715a-48a8-8f54-ab9fbe9bc310”,
“name”: “Submit to ComfyUI”,
“type”: “n8n-nodes-base.httpRequest”,
“typeVersion”: 4.2,
“position”: [
208,
224
]
},
{
“parameters”: {
“jsCode”: “const promptId = $json.prompt_id;\nif (!promptId) {\n throw new Error('No prompt_id. ComfyUI said: ’ + JSON.stringify($json));\n}\nconst buildData = $(‘Build ComfyUI Payload’).first().json;\nreturn [{\n json: {\n prompt_id: promptId,\n outputFileName: buildData.outputFileName\n }\n}];”
},
“id”: “c2707be6-d0bd-493e-af00-ec8af85959b8”,
“name”: “Store Prompt ID”,
“type”: “n8n-nodes-base.code”,
“typeVersion”: 2,
“position”: [
448,
224
]
},
{
“parameters”: {
“amount”: 30
},
“id”: “22a843a9-595c-43e0-9cdb-2e2bbd4338d4”,
“name”: “Wait 30s”,
“type”: “n8n-nodes-base.wait”,
“typeVersion”: 1.1,
“position”: [
688,
224
],
“webhookId”: “zturbo-v11-wait”
},
{
“parameters”: {
“url”: “=http://127.0.0.1:8000/history/{{ $json.prompt_id }}”,
“options”: {
“timeout”: 15000
}
},
“id”: “8bf29c3d-d0cd-4711-8bcb-9ca6bad18642”,
“name”: “Poll ComfyUI History”,
“type”: “n8n-nodes-base.httpRequest”,
“typeVersion”: 4.2,
“position”: [
256,
480
]
},
{
“parameters”: {
“jsCode”: “const storeData = $(‘Store Prompt ID’).first().json;\nconst promptId = storeData.prompt_id;\nconst outputFileName = storeData.outputFileName;\nconst history = $json;\n\nif (!history[promptId]) {\n throw new Error(prompt_id \"${promptId}\" not found in history. Keys: [${Object.keys(history).join(', ')}]);\n}\n\nconst jobHistory = history[promptId];\n\n// ComfyUI v7 stores outputs directly under jobHistory.outputs\nif (!jobHistory.outputs || Object.keys(jobHistory.outputs).length === 0) {\n throw new Error('No outputs yet. Status: ’ + JSON.stringify(jobHistory.status || {}));\n}\n\nlet imageInfo = null;\nfor (const nodeId of Object.keys(jobHistory.outputs)) {\n const out = jobHistory.outputs[nodeId];\n if (out && out.images && out.images.length > 0) {\n imageInfo = out.images[0];\n break;\n }\n}\n\nif (!imageInfo) {\n throw new Error('No images in outputs: ’ + JSON.stringify(jobHistory.outputs));\n}\n\nconst filename = imageInfo.filename;\nconst subfolder = imageInfo.subfolder || ‘’;\nconst type = imageInfo.type || ‘output’;\n\n// HTTP download URL — works even though disk read is blocked\nconst downloadUrl = ‘http://127.0.0.1:8000/view?filename=’ + encodeURIComponent(filename) + ‘&subfolder=’ + encodeURIComponent(subfolder) + ‘&type=’ + type;\n\n// Save destination inside n8n allowed folder\nconst savePath = ‘C:\\Users\\Whisp\\.n8n-files\\Images\\output_images\\’ + outputFileName + ‘.png’;\n\nreturn [{\n json: { promptId, outputFileName, filename, downloadUrl, savePath }\n}];”
},
“id”: “74589e98-4b80-497c-bc41-6c0311b908b0”,
“name”: “Extract Image Info”,
“type”: “n8n-nodes-base.code”,
“typeVersion”: 2,
“position”: [
496,
480
]
},
{
“parameters”: {
“url”: “={{ $json.downloadUrl }}”,
“options”: {
“response”: {
“response”: {
“responseFormat”: “file”
}
},
“timeout”: 60000
}
},
“id”: “28aaffa3-c7d0-4586-87f2-e26799dee81e”,
“name”: “Download Image”,
“type”: “n8n-nodes-base.httpRequest”,
“typeVersion”: 4.2,
“position”: [
736,
480
]
},
{
“parameters”: {
“jsCode”: “// Rename binary to our desired output filename\nconst extractData = $(‘Extract Image Info’).first().json;\nconst item = $input.first();\n\nconst binaryKeys = Object.keys(item.binary || {});\nif (binaryKeys.length === 0) {\n throw new Error('No binary data from download. URL was: ’ + extractData.downloadUrl);\n}\n\nconst binaryKey = binaryKeys[0];\nconst imageData = item.binary[binaryKey];\n\nreturn [{\n json: {\n savePath: extractData.savePath,\n outputFileName: extractData.outputFileName\n },\n binary: {\n image: {\n …imageData,\n fileName: extractData.outputFileName + ‘.png’,\n mimeType: ‘image/png’\n }\n }\n}];”
},
“id”: “cf06d78d-e812-4870-9706-e4737d1b7189”,
“name”: “Prepare File for Save”,
“type”: “n8n-nodes-base.code”,
“typeVersion”: 2,
“position”: [
256,
704
]
},
{
“parameters”: {
“operation”: “write”,
“fileName”: “={{ $json.savePath }}”,
“dataPropertyName”: “image”,
“options”: {
“append”: false
}
},
“id”: “c027ba08-b780-4c79-b2b2-a8d39a3c1817”,
“name”: “Save Image to Disk”,
“type”: “n8n-nodes-base.readWriteFile”,
“typeVersion”: 1,
“position”: [
496,
704
]
},
{
“parameters”: {
“jsCode”: “const data = $(‘Prepare File for Save’).first().json;\nreturn [{ json: { status: ‘success’, savedAs: data.savePath } }];”
},
“id”: “4bdfad5d-b814-4dcc-8432-1f40f2467dfe”,
“name”: “Done”,
“type”: “n8n-nodes-base.code”,
“typeVersion”: 2,
“position”: [
736,
704
]
}
],
“pinData”: {},
“connections”: {
“Manual Trigger”: {
“main”: [
[
{
“node”: “Read All Prompt Files”,
“type”: “main”,
“index”: 0
}
]
]
},
“Read All Prompt Files”: {
“main”: [
[
{
“node”: “Parse Prompts”,
“type”: “main”,
“index”: 0
}
]
]
},
“Parse Prompts”: {
“main”: [
[
{
“node”: “Build ComfyUI Payload”,
“type”: “main”,
“index”: 0
}
]
]
},
“Build ComfyUI Payload”: {
“main”: [
[
{
“node”: “Submit to ComfyUI”,
“type”: “main”,
“index”: 0
}
]
]
},
“Submit to ComfyUI”: {
“main”: [
[
{
“node”: “Store Prompt ID”,
“type”: “main”,
“index”: 0
}
]
]
},
“Store Prompt ID”: {
“main”: [
[
{
“node”: “Wait 30s”,
“type”: “main”,
“index”: 0
}
]
]
},
“Wait 30s”: {
“main”: [
[
{
“node”: “Poll ComfyUI History”,
“type”: “main”,
“index”: 0
}
]
]
},
“Poll ComfyUI History”: {
“main”: [
[
{
“node”: “Extract Image Info”,
“type”: “main”,
“index”: 0
}
]
]
},
“Extract Image Info”: {
“main”: [
[
{
“node”: “Download Image”,
“type”: “main”,
“index”: 0
}
]
]
},
“Download Image”: {
“main”: [
[
{
“node”: “Prepare File for Save”,
“type”: “main”,
“index”: 0
}
]
]
},
“Prepare File for Save”: {
“main”: [
[
{
“node”: “Save Image to Disk”,
“type”: “main”,
“index”: 0
}
]
]
},
“Save Image to Disk”: {
“main”: [
[
{
“node”: “Done”,
“type”: “main”,
“index”: 0
}
]
]
}
},
“active”: false,
“settings”: {
“executionOrder”: “v1”,
“binaryMode”: “separate”
},
“versionId”: “16e78333-3f27-4307-a0b4-67c4aed43615”,
“meta”: {
“instanceId”: “8c7a0aff9b7b28efe5045c81356a27e0291f8c14e6f7ff4f2b43230529ce67fa”
},
“id”: “1EgMBrSuhhccYR9p”,
“tags”:
}

Did you enable local file access?
What is your setup? npm or docker? n8n version?
Please provide as much details as possible

1 Like

npm, sorry i am trying to upload my node here , it wont allow because i am still a new user here.

this my setup:

| Step | Function | Description

| Manual Trigger | Start | Begins the workflow manually. |
| Read All Prompt Files | Input | Reads prompt files from disk (text or JSON). |
| Parse Prompts | Processing | Extracts structured data from the prompt files. |
| Build ComfyUI Payload | Preparation | Constructs a payload compatible with ComfyUI’s API. |
| Submit to ComfyUI | Execution | Sends the payload via HTTP POST to http://127.0.0.1:8000/... (local ComfyUI server). |
| Store Prompt ID | Tracking | Saves the returned prompt ID for later reference. |
| Wait 30s | Delay | Pauses to allow ComfyUI to finish image generation. |
| Poll ComfyUI History | Retrieval | Queries ComfyUI for the generation history using the stored prompt ID. |
| Extract Image Info | Data Handling | Pulls metadata (image path, name, etc.) from the history. |
| Download Image | Output | Fetches the generated image from ComfyUI. |
| Prepare File for Save | Formatting | Prepares the image file for local storage (e.g., naming, path setup). |
| Save Image to Disk | Storage | Writes the image to disk. |
| Done | Completion | Marks the workflow as finished. |

thank you

@wee welcome to the n8n community

Before the “Send to ComfyUI” node, verify that the output of the “Build ComfyUI Payload” node contains the actual text from the txt file in the correct field of the ComfyUI workflow — typically the inputs.text field of a CLIPTextEncode node. If the payload still contains the default ComfyUI workflow prompt, it will continue generating the default/random image. A good test is to add a very specific prompt in the .txt, such as red cube on a white table, no people, and confirm in the HTTP Request output whether that text appears exactly in the JSON sent to ComfyUI.

thankyou , ill try it out .