|
|
||
|---|---|---|
| .. | ||
| __tests__ | ||
| rules | ||
| types | ||
| breaking-changes.controller.ts | ||
| breaking-changes.module.ts | ||
| breaking-changes.rule-registry.service.ts | ||
| breaking-changes.service.ts | ||
| README.md | ||
Breaking Changes Detection Module
A rule-based system for detecting breaking changes before migrating to a new n8n version.
Overview
This module scans the n8n instance (workflows, configuration, environment) to identify issues that will be affected by breaking changes in the target version.
Architecture
breaking-changes/
types/
rule.types.ts # Core interfaces and enums
detection.types.ts # Report types
index.ts
rules/
v2/ # V2-specific rules
removed-nodes.rule.ts
process-env-access.rule.ts
file-access.rule.ts
...
index.ts # Side-effect imports for all rules
breaking-changes.service.ts # Detection orchestration
breaking-changes.rule-registry.service.ts # Rule management
breaking-changes.controller.ts # REST API
breaking-changes.module.ts # Module definition
Registration
Rules are registered at startup using the @BreakingChangeRule decorator from
@n8n/decorators (following the same pattern as @BackendModule / ModuleMetadata).
Each rule file is explicitly imported in rules/index.ts as a side-effect
import, which triggers the decorator and registers the rule class. Because the
decorator lives in @n8n/decorators, rules can be defined anywhere in the codebase.
Module.init()
→ import './rules' side-effect imports of all rule files
→ @BreakingChangeRule fires on each class
→ BreakingChangeRuleMetadata.register()
→ import controller
→ BreakingChangeService constructor
→ registerRules() reads from metadata, resolves via DI
→ RuleRegistry.registerAll()
API Endpoint
Detect Breaking Changes
GET /breaking-changes/report?version=v2
Returns:
{
"report": {
"generatedAt": "2025-10-17T00:00:00.000Z",
"targetVersion": "v2",
"currentVersion": "1.x.x",
"instanceResults": [
{
"ruleId": "process-env-access-v2",
"ruleTitle": "Process Environment Access Restrictions",
"ruleDescription": "Access to process.env is now restricted",
"ruleSeverity": "high",
"instanceIssues": [
{
"title": "Environment access detected",
"description": "Workflows using process.env may be affected",
"level": "warning"
}
],
"recommendations": [
{
"action": "Review environment variable usage",
"description": "Update workflows to use secure environment variable access"
}
]
}
],
"workflowResults": [
{
"ruleId": "removed-nodes-v2",
"ruleTitle": "Removed Deprecated Nodes",
"ruleDescription": "Several deprecated nodes have been removed",
"ruleSeverity": "critical",
"affectedWorkflows": [
{
"id": "wf-001",
"name": "Customer Onboarding",
"active": true,
"numberOfExecutions": 142,
"lastUpdatedAt": "2025-10-15T10:30:00.000Z",
"lastExecutedAt": "2025-10-16T14:22:00.000Z",
"issues": [
{
"title": "Node 'n8n-nodes-base.spontit' with name 'Spontit' has been removed",
"description": "The node type 'n8n-nodes-base.spontit' is no longer available",
"level": "error",
"nodeId": "node-123",
"nodeName": "Spontit"
}
]
}
],
"recommendations": [
{
"action": "Update affected workflows",
"description": "Replace removed nodes with their updated versions or alternatives"
}
]
}
]
},
"shouldCache": false
}
Rule Types
The system supports three types of rules:
Workflow Rules (IBreakingChangeWorkflowRule)
- Purpose: Check individual workflows for breaking changes
- Methods:
getMetadata(): Returns rule metadata (version, title, description, severity, etc.)detectWorkflow(workflow, nodesGroupedByType): Checks a single workflow and returns issuesgetRecommendations(workflowResults): Returns recommendations based on detected issues
- Returns:
WorkflowDetectionReportwith workflow-specific issues - Example Use Cases: Removed nodes, deprecated node features, changed node behavior
Instance Rules (IBreakingChangeInstanceRule)
- Purpose: Check instance-level configuration and environment
- Methods:
getMetadata(): Returns rule metadata (version, title, description, severity, etc.)detect(): Checks the entire instance and returns issues
- Returns:
InstanceDetectionReportwith instance-level issues and recommendations - Example Use Cases: Environment variable requirements, database version checks, configuration changes
Batch Workflow Rules (IBreakingChangeBatchWorkflowRule)
- Purpose: Correlate data across multiple workflows (e.g., detecting parent workflows that call sub-workflows with specific characteristics)
- Methods:
getMetadata(): Returns rule metadatacollectWorkflowData(workflow, nodesGroupedByType): Called per workflow during scanningproduceReport(): Called after all workflows scanned to produce final reportreset(): Resets internal state before a new detection rungetRecommendations(workflowResults): Returns recommendations
- Returns:
BatchWorkflowDetectionReport
Adding Rules
Adding a Rule to an Existing Version
- Create a new
.rule.tsfile in the appropriate version directory. - Add a side-effect import for it in
rules/index.ts.
The @BreakingChangeRule decorator handles registration automatically on import.
Workflow Rule Example
Create rules/v2/my-workflow-rule.rule.ts:
import type { BreakingChangeAffectedWorkflow, BreakingChangeRecommendation } from '@n8n/api-types';
import type { WorkflowEntity } from '@n8n/db';
import type { INode } from 'n8n-workflow';
import { BreakingChangeRule } from '@n8n/decorators';
import type {
BreakingChangeRuleMetadata,
IBreakingChangeWorkflowRule,
WorkflowDetectionReport,
} from '../../types';
import { BreakingChangeCategory } from '../../types';
@BreakingChangeRule({ version: 'v2' })
export class MyWorkflowRule implements IBreakingChangeWorkflowRule {
id: string = 'my-workflow-rule-v2';
getMetadata(): BreakingChangeRuleMetadata {
return {
version: 'v2',
title: 'My Workflow Breaking Change',
description: 'Description of what changed in workflows',
category: BreakingChangeCategory.workflow,
severity: 'high',
documentationUrl: 'https://docs.n8n.io/migration/v2/...',
};
}
async getRecommendations(
_workflowResults: BreakingChangeAffectedWorkflow[],
): Promise<BreakingChangeRecommendation[]> {
return [
{
action: 'Update affected workflows',
description: 'Replace or update the affected nodes',
},
];
}
async detectWorkflow(
_workflow: WorkflowEntity,
nodesGroupedByType: Map<string, INode[]>,
): Promise<WorkflowDetectionReport> {
const affectedNodes = nodesGroupedByType.get('n8n-nodes-base.someNode') ?? [];
if (affectedNodes.length === 0) {
return { isAffected: false, issues: [] };
}
return {
isAffected: true,
issues: affectedNodes.map((node) => ({
title: `Node '${node.type}' with name '${node.name}' is affected`,
description: 'This node requires updates for v2 compatibility',
level: 'warning',
nodeId: node.id,
nodeName: node.name,
})),
};
}
}
Instance Rule Example
Create rules/v2/my-instance-rule.rule.ts:
import { BreakingChangeRule } from '@n8n/decorators';
import type {
BreakingChangeRuleMetadata,
IBreakingChangeInstanceRule,
InstanceDetectionReport,
} from '../../types';
import { BreakingChangeCategory } from '../../types';
@BreakingChangeRule({ version: 'v2' })
export class MyInstanceRule implements IBreakingChangeInstanceRule {
id: string = 'my-instance-rule-v2';
getMetadata(): BreakingChangeRuleMetadata {
return {
version: 'v2',
title: 'My Instance Breaking Change',
description: 'Description of what changed at instance level',
category: BreakingChangeCategory.instance,
severity: 'medium',
documentationUrl: 'https://docs.n8n.io/migration/v2/...',
};
}
async detect(): Promise<InstanceDetectionReport> {
const hasIssue = false; // Your detection logic here
if (!hasIssue) {
return { isAffected: false, instanceIssues: [], recommendations: [] };
}
return {
isAffected: true,
instanceIssues: [
{
title: 'Configuration issue detected',
description: 'Description of the issue',
level: 'warning',
},
],
recommendations: [
{
action: 'Fix the configuration',
description: 'Steps to resolve the issue',
},
],
};
}
}
The rule will be automatically:
- Registered in
BreakingChangeRuleMetadataby the@BreakingChangeRuledecorator - Instantiated via DI and added to
RuleRegistrywhen the service starts - Available for detection when calling the API with the matching version
Adding a New Version
To add breaking changes for a new version (e.g., v3):
-
Create the version directory:
mkdir -p packages/cli/src/modules/breaking-changes/rules/v3 -
Add rule files with
@BreakingChangeRule({ version: 'v3' }). -
Add side-effect imports for the new rule files in
rules/index.ts.