This workflow corresponds to n8n.io template #8112 — we link there as the canonical source.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "Wyw2TmhKVujBRhkZ",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Sync Android drawable assets from Figma to GitHub",
"tags": [],
"nodes": [
{
"id": "b9ed0516-1d34-499b-85ba-7e304129b116",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"position": [
660,
-280
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineAll"
},
"typeVersion": 3.2
},
{
"id": "8c08ddf1-e081-425c-bdb1-b46e28f48ebf",
"name": "Download Each Image from the Figma Export URL",
"type": "n8n-nodes-base.httpRequest",
"position": [
1320,
-355
],
"parameters": {
"url": "={{ $json[\"url\"] }}",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"typeVersion": 4.2
},
{
"id": "139ce28e-570d-443d-a347-bef3089e6e1e",
"name": "get figma Url",
"type": "n8n-nodes-base.httpRequest",
"position": [
880,
-355
],
"parameters": {
"url": "=https://api.figma.com/v1/images/FIGMA_PROJECT_ID?ids={{$json[\"id\"]}}&format=png&scale={{$json[\"scale\"]}}",
"options": {},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Figma-Token",
"value": "FIGMA_TOKEN"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "383243fc-1bd0-4968-af5e-fb6ba09e80f9",
"name": "Merge1",
"type": "n8n-nodes-base.merge",
"position": [
1560,
-220
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2,
"alwaysOutputData": true
},
{
"id": "087cce4c-2102-48f8-bee1-69468fceeec9",
"name": "If",
"type": "n8n-nodes-base.if",
"position": [
1840,
-220
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "4f1fd504-3119-4fe0-bb8f-6af824494d41",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{$itemIndex}}",
"rightValue": 0
}
]
}
},
"typeVersion": 2.2
},
{
"id": "258614f5-1704-4972-bbd4-e0bf8f4126d3",
"name": "Get Figma Export URL",
"type": "n8n-nodes-base.httpRequest",
"position": [
220,
-280
],
"parameters": {
"url": "https://api.figma.com/v1/files/FIGMA_PROJECT_ID?ids=2-20347",
"options": {},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Figma-Token",
"value": "FIGMA_TOKEN"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "417bd211-81b9-4f1c-9cdf-15b01a2d39ab",
"name": "Execute workflow",
"type": "n8n-nodes-base.manualTrigger",
"position": [
0,
-280
],
"parameters": {},
"typeVersion": 1
},
{
"id": "03ff18dd-880b-4930-9d61-6e16d5e08078",
"name": "Find Icons & Buttons",
"type": "n8n-nodes-base.code",
"position": [
440,
-380
],
"parameters": {
"jsCode": "function findIconsAndButtons(nodes, parentChain = []) {\n let matches = [];\n\n for (const node of nodes) {\n const fullPath = [...parentChain, node.name].join('/');\n\n // If current node is a match\n if (typeof node.name === 'string' && /icon|button/i.test(node.name)) {\n matches.push({\n id: node.id,\n name: node.name,\n type: node.type,\n fullPath: fullPath,\n exportSettings: node.exportSettings || null,\n });\n }\n\n // Recurse into children if they exist\n if (node.children && Array.isArray(node.children)) {\n matches.push(...findIconsAndButtons(node.children, [...parentChain, node.name]));\n }\n }\n\n return matches;\n}\n\n// Start from the root document children\nconst rootNode = items[0].json.document;\nconst canvas = rootNode.children.find(child => child.type === 'CANVAS');\nconst frame = canvas.children.find(child => child.type === 'FRAME' && /forgot password/i.test(child.name));\n\nif (!frame || !frame.children) {\n return [];\n}\n\n// Recursively collect icons and buttons\nconst results = findIconsAndButtons(frame.children);\n\nreturn results.map(node => ({\n json: node\n}));"
},
"typeVersion": 2,
"alwaysOutputData": true
},
{
"id": "6ea0e89f-aeef-46b0-b26b-22dcace571de",
"name": "Predefine drawable folders",
"type": "n8n-nodes-base.code",
"position": [
440,
-180
],
"parameters": {
"jsCode": "return [\n { json: { folder: 'drawable-mdpi', scale: '1' } },\n { json: { folder: 'drawable-hdpi', scale: '1.5' } },\n { json: { folder: 'drawable-xhdpi', scale: '2' } },\n { json: { folder: 'drawable-xxhdpi', scale: '3' } }\n];"
},
"typeVersion": 2
},
{
"id": "1ac6faec-8395-4f4e-bea1-82344b1a4fd8",
"name": "Filter nullable url of nodes",
"type": "n8n-nodes-base.code",
"position": [
1100,
-360
],
"parameters": {
"jsCode": "// Filter valid images and map to { nodeId, url }\nconst results = [];\n\nfor (const item of items) {\n const images = item.json.images;\n\n for (const nodeId in images) {\n const url = images[nodeId];\n\n if (url) {\n results.push({\n json: {\n nodeId,\n url\n }\n });\n }\n }\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "053297b8-705d-42b9-9531-16bf91629f93",
"name": "Edit File names",
"type": "n8n-nodes-base.code",
"position": [
1700,
-360
],
"parameters": {
"jsCode": "return items.map(item => {\n const name = item.json.name || \"asset\";\n const folder = item.json.folder || \"drawable-mdpi\";\n \n item.json.path = `app/src/main/res/${folder}/${name.toLowerCase().replace(/[^a-z0-9]/g, \"_\")}.png`;\n item.json.commitMessage = `Add asset: ${name}.png to ${folder}`;\n item.json.branch = \"add-assets-from-figma\";\n item.json.repoOwner = \"REPO_OWNER\";\n item.json.repoName = \"REPO_NAME\";\n\n return item;\n});"
},
"typeVersion": 2
},
{
"id": "1678d236-4bab-4b39-a553-cd67f9cffe1a",
"name": "Prepare Pull Request",
"type": "n8n-nodes-base.httpRequest",
"position": [
2040,
-220
],
"parameters": {
"url": "https://api.github.com/repos/REPO_OWNER/REPO_NAME/pulls",
"method": "POST",
"options": {},
"jsonBody": "{\n \"title\": \"Add drawable assets from Figma\",\n \"head\": \"add-assets-from-figma\",\n \"base\": \"main\",\n \"body\": \"This PR contains Android drawable assets exported from Figma in all resolutions.\"\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer YOUR_TOKEN_HERE"
},
{
"name": "Accept",
"value": "application/vnd.github+json"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "4ccbac73-ffba-45a7-a6fe-a77b8021480f",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-40,
-460
],
"parameters": {
"width": 2280,
"height": 440,
"content": "\nSync Android drawable assets from Figma to GitHub via PR (multi\u2011density PNG)"
},
"typeVersion": 1
},
{
"id": "09523583-b2db-40d7-97df-798608513226",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-40,
60
],
"parameters": {
"width": 2280,
"height": 760,
"content": "#\nNode Name\nDescription\n\n1 \ud83d\udd01 Execute Flow\nTrigger node to start the automation manually or via webhook/schedule.\n\n2 \ud83c\udfa8 Get Figma Export URLs\nFetches Figma export URLs (PNG/SVG) for all components from a specified file or parent node.\n\n3 \ud83e\udde0 Find Icons & Buttons\nFilters nodes by name or type to extract only relevant UI components like \u201cIcon\u201d and \u201cButton\u201d.\n\n4 \ud83d\udcc2 Predefine Drawable Folders\nCreates static Android drawable folder list (mdpi, hdpi, etc.) as JSON for merging later.\n\n5 \ud83d\udd17 Merge Metadata & Folders\nMerges filtered Figma nodes with predefined Android folder structure for each resolution.\n\n6 \ud83c\udf10 Get Figma Image URLs\nCalls Figma export API with IDs from merged metadata to retrieve actual exportable image URLs.\n\n7 \ud83d\udeab Filter Empty Image URLs\nRemoves any nodes where export URL is missing/null to avoid failed downloads or commits.\n\n8 \ud83d\udce5 Download Figma Images\nDownloads binary image files from export URLs for all filtered nodes across densities.\n\n9 \ud83e\uddec Merge Metadata & Images\nMerges previously prepared metadata (drawable folder, file name) with actual downloaded image files.\n\n10 \ud83d\udcdd Edit File Names\nRenames files based on naming conventions (e.g., lowercase, no spaces, append _icon if needed).\n\n11 \ud83d\udd04 If: Pull Request Created?\nPrevents duplicate pull requests by checking if one already exists for the same branch or purpose.\n\n12 \ud83d\ude80 Prepare Pull Request\nCommits all images to GitHub in proper folders and creates a clean Pull Request into the main branch.\n\n"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "da71a6f8-28a7-467f-998e-a4fef0700dc8",
"connections": {
"If": {
"main": [
[
{
"node": "Prepare Pull Request",
"type": "main",
"index": 0
}
]
]
},
"Merge": {
"main": [
[
{
"node": "get figma Url",
"type": "main",
"index": 0
},
{
"node": "Merge1",
"type": "main",
"index": 1
}
]
]
},
"Merge1": {
"main": [
[
{
"node": "Edit File names",
"type": "main",
"index": 0
}
]
]
},
"get figma Url": {
"main": [
[
{
"node": "Filter nullable url of nodes",
"type": "main",
"index": 0
}
]
]
},
"Edit File names": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"Execute workflow": {
"main": [
[
{
"node": "Get Figma Export URL",
"type": "main",
"index": 0
}
]
]
},
"Find Icons & Buttons": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Get Figma Export URL": {
"main": [
[
{
"node": "Find Icons & Buttons",
"type": "main",
"index": 0
},
{
"node": "Predefine drawable folders",
"type": "main",
"index": 0
}
]
]
},
"Predefine drawable folders": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Filter nullable url of nodes": {
"main": [
[
{
"node": "Download Each Image from the Figma Export URL",
"type": "main",
"index": 0
}
]
]
},
"Download Each Image from the Figma Export URL": {
"main": [
[
{
"node": "Merge1",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This n8n workflow automatically fetches design assets (icons, buttons) from Figma, exports them into Android drawable folder formats based on resolution (e.g., , , etc.) and commits them to a GitHub branch, creating a Pull Request with all updates. Android / Flutter developers…
Source: https://n8n.io/workflows/8112/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow allows you to import any workflow from a file or another n8n instance and map the credentials easily. A multi-form setup guides you through the entire process At the beginning you have t
[n8n] Advanced URL Parsing and Shortening Workflow - Switchy.io Integration. Uses splitInBatches, stickyNote, httpRequest, html. Event-driven trigger; 56 nodes.
[](https://youtu.be/c7yCZhmMjtI)
This automation organizes your n8n workflows files into categorizes (Active, Template, Done, Archived) and uploads them directly to a categorized Google Drive folders. It is designed to help users man
Create Animated Stories using GPT-4o-mini, Midjourney, Kling and Creatomate API. Uses httpRequest. Event-driven trigger; 51 nodes.