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 →
{
"name": "Module Dependency Analysis",
"nodes": [
{
"parameters": {
"path": "module-analysis",
"httpMethod": "POST",
"authentication": "none",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook-trigger",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
240,
300
]
},
{
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 2
}
]
}
},
"id": "schedule-trigger",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
240,
500
]
},
{
"parameters": {
"url": "http://host.docker.internal:3010/api/execute",
"method": "POST",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "command",
"value": "cd /workspace && npx depcruise --output-type json ."
}
]
},
"options": {}
},
"id": "run-depcruise",
"name": "Run Dependency Cruiser",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
460,
400
]
},
{
"parameters": {
"jsCode": "// Parse dependency-cruiser output and build enhanced analysis\nconst response = $input.item.json;\nconst rawData = JSON.parse(response.stdout);\n\nconst modules = {};\nconst dependencies = [];\nconst dependents = {};\n\n// Helper: Get package from path\nfunction getPackage(filePath) {\n if (filePath.startsWith('apps/whatsfresh/')) return 'whatsfresh';\n if (filePath.startsWith('apps/server/')) return 'server';\n if (filePath.startsWith('apps/admin/')) return 'admin';\n if (filePath.startsWith('apps/studio/')) return 'studio';\n if (filePath.startsWith('apps/login/')) return 'login';\n if (filePath.startsWith('packages/shared-imports/')) return 'shared-imports';\n if (filePath.startsWith('packages/db-connect/')) return 'db-connect';\n return 'other';\n}\n\n// Helper: Get module type from path\nfunction getModuleType(filePath) {\n if (filePath.includes('/controller/')) return 'controller';\n if (filePath.includes('/component/') || filePath.includes('/components/')) return 'component';\n if (filePath.includes('/util/') || filePath.includes('/utils/')) return 'utility';\n if (filePath.includes('/route/') || filePath.includes('/routes/')) return 'routing';\n if (filePath.includes('.config.')) return 'config';\n if (filePath.includes('.test.') || filePath.includes('.spec.')) return 'test';\n return 'module';\n}\n\n// Process dependency-cruiser data - format is: { modules: [{source: \"file.js\", dependencies: [{resolved: \"dep.js\"}]}] }\nfor (const module of rawData.modules || []) {\n const filePath = module.source;\n const pkg = getPackage(filePath);\n const moduleType = getModuleType(filePath);\n \n // Extract dependency paths (only local files, exclude node_modules)\n const deps = (module.dependencies || [])\n .map(d => d.resolved)\n .filter(d => d && !d.includes('node_modules') && (d.startsWith('apps/') || d.startsWith('packages/')));\n\n modules[filePath] = {\n file_path: filePath,\n package: pkg,\n module_type: moduleType,\n dependencies: deps,\n dependency_count: deps.length\n };\n\n // Build dependencies and reverse map\n for (const depPath of deps) {\n dependencies.push({\n from_path: filePath,\n to_path: depPath\n });\n\n // Build reverse dependency map\n if (!dependents[depPath]) {\n dependents[depPath] = [];\n }\n dependents[depPath].push(filePath);\n }\n}\n\n// Calculate dependent counts and blast radius\nfor (const [filePath, moduleData] of Object.entries(modules)) {\n const dependentCount = (dependents[filePath] || []).length;\n \n moduleData.dependent_count = dependentCount;\n \n // Calculate blast radius\n if (dependentCount >= 8) {\n moduleData.blast_radius = 'high';\n } else if (dependentCount >= 4) {\n moduleData.blast_radius = 'medium';\n } else {\n moduleData.blast_radius = 'low';\n }\n}\n\n// Batch modules (100 per batch)\nconst BATCH_SIZE = 100;\nconst moduleArray = Object.values(modules);\nconst moduleBatches = [];\nfor (let i = 0; i < moduleArray.length; i += BATCH_SIZE) {\n moduleBatches.push(moduleArray.slice(i, i + BATCH_SIZE));\n}\n\n// Batch dependencies\nconst depBatches = [];\nfor (let i = 0; i < dependencies.length; i += BATCH_SIZE) {\n depBatches.push(dependencies.slice(i, i + BATCH_SIZE));\n}\n\nconsole.log(`Processed ${moduleArray.length} modules in ${moduleBatches.length} batches`);\nconsole.log(`Processed ${dependencies.length} dependencies in ${depBatches.length} batches`);\n\nreturn {\n json: {\n moduleBatches,\n depBatches,\n totalModules: moduleArray.length,\n totalDependencies: dependencies.length\n }\n};"
},
"id": "analyze-dependencies",
"name": "Analyze Dependencies",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
400
]
},
{
"parameters": {
"batchSize": 100,
"options": {}
},
"id": "split-module-batches",
"name": "Split Module Batches",
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
900,
300
]
},
{
"parameters": {
"jsCode": "// Split In Batches already grouped items - just serialize them\nconst allItems = $input.all();\nconst batch = allItems.map(item => item.json);\n\nreturn {\n json: {\n modulesJson: JSON.stringify(batch),\n batchSize: batch.length\n }\n};"
},
"id": "prepare-module-batch",
"name": "Prepare Module Batch",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1120,
300
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "CALL api_wf.sp_module_load(?, 'n8n-automation')",
"options": {
"queryParameters": "={{ $json.modulesJson }}"
}
},
"id": "load-modules",
"name": "Load Modules",
"type": "n8n-nodes-base.mySql",
"typeVersion": 2.5,
"position": [
1340,
300
],
"credentials": {
"mySql": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"batchSize": 100,
"options": {}
},
"id": "split-dep-batches",
"name": "Split Dependency Batches",
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
900,
500
]
},
{
"parameters": {
"jsCode": "// Split In Batches already grouped items - just serialize them\nconst allItems = $input.all();\nconst batch = allItems.map(item => item.json);\n\nreturn {\n json: {\n depsJson: JSON.stringify(batch),\n batchSize: batch.length\n }\n};"
},
"id": "prepare-dep-batch",
"name": "Prepare Dependency Batch",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1120,
500
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "CALL api_wf.sp_module_map(?, 'n8n-automation')",
"options": {
"queryParameters": "={{ $json.depsJson }}"
}
},
"id": "map-dependencies",
"name": "Map Dependencies",
"type": "n8n-nodes-base.mySql",
"typeVersion": 2.5,
"position": [
1340,
500
],
"credentials": {
"mySql": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"respondWith": "text",
"responseBody": "=Module analysis complete. Processed modules and dependencies.",
"options": {}
},
"id": "respond-webhook",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
1560,
300
]
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Run Madge Analysis",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Run Madge Analysis",
"type": "main",
"index": 0
}
]
]
},
"Run Madge Analysis": {
"main": [
[
{
"node": "Analyze Dependencies",
"type": "main",
"index": 0
}
]
]
},
"Analyze Dependencies": {
"main": [
[
{
"node": "Split Module Batches",
"type": "main",
"index": 0
}
],
[
{
"node": "Split Dependency Batches",
"type": "main",
"index": 0
}
]
]
},
"Split Module Batches": {
"main": [
[
{
"node": "Prepare Module Batch",
"type": "main",
"index": 0
}
]
]
},
"Prepare Module Batch": {
"main": [
[
{
"node": "Load Modules",
"type": "main",
"index": 0
}
]
]
},
"Load Modules": {
"main": [
[
{
"node": "Split Module Batches",
"type": "main",
"index": 0
}
],
null,
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Split Dependency Batches": {
"main": [
[
{
"node": "Prepare Dependency Batch",
"type": "main",
"index": 0
}
]
]
},
"Prepare Dependency Batch": {
"main": [
[
{
"node": "Map Dependencies",
"type": "main",
"index": 0
}
]
]
},
"Map Dependencies": {
"main": [
[
{
"node": "Split Dependency Batches",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
mySql
About this workflow
Module Dependency Analysis. Uses scheduleTrigger, httpRequest, splitInBatches, mySql. Webhook trigger; 11 nodes.
Source: https://github.com/pchambless/wf-monorepo/blob/47cd16469735c59a12b7c76e2552861f899e335d/.n8n/workflows/module-dependency-analysis.json — original creator credit. Request a take-down →