14 KiB
Property Dependencies Guide
Deep dive into n8n property dependencies and displayOptions mechanism.
What Are Property Dependencies?
Definition: Rules that control when fields are visible or required based on other field values.
Mechanism: displayOptions in node schema
Purpose:
- Show relevant fields only
- Hide irrelevant fields
- Simplify configuration UX
- Prevent invalid configurations
displayOptions Structure
Basic Format
{
"name": "fieldName",
"type": "string",
"displayOptions": {
"show": {
"otherField": ["value1", "value2"]
}
}
}
Translation: Show fieldName when otherField equals "value1" OR "value2"
Show vs Hide
show (Most Common)
Show field when condition matches:
{
"name": "body",
"displayOptions": {
"show": {
"sendBody": [true]
}
}
}
Meaning: Show body when sendBody = true
hide (Less Common)
Hide field when condition matches:
{
"name": "advanced",
"displayOptions": {
"hide": {
"simpleMode": [true]
}
}
}
Meaning: Hide advanced when simpleMode = true
Multiple Conditions (AND Logic)
{
"name": "body",
"displayOptions": {
"show": {
"sendBody": [true],
"method": ["POST", "PUT", "PATCH"]
}
}
}
Meaning: Show body when:
sendBody = trueANDmethod IN (POST, PUT, PATCH)
All conditions must match (AND logic)
Multiple Values (OR Logic)
{
"name": "someField",
"displayOptions": {
"show": {
"method": ["POST", "PUT", "PATCH"]
}
}
}
Meaning: Show someField when:
method = POSTORmethod = PUTORmethod = PATCH
Any value matches (OR logic)
Common Dependency Patterns
Pattern 1: Boolean Toggle
Use case: Optional feature flag
Example: HTTP Request sendBody
// Field: sendBody (boolean)
{
"name": "sendBody",
"type": "boolean",
"default": false
}
// Field: body (depends on sendBody)
{
"name": "body",
"displayOptions": {
"show": {
"sendBody": [true]
}
}
}
Flow:
- User sees sendBody checkbox
- When checked → body field appears
- When unchecked → body field hides
Pattern 2: Resource/Operation Cascade
Use case: Different operations show different fields
Example: Slack message operations
// Operation: post
{
"name": "channel",
"displayOptions": {
"show": {
"resource": ["message"],
"operation": ["post"]
}
}
}
// Operation: update
{
"name": "messageId",
"displayOptions": {
"show": {
"resource": ["message"],
"operation": ["update"]
}
}
}
Flow:
- User selects resource="message"
- User selects operation="post" → sees channel
- User changes to operation="update" → channel hides, messageId shows
Pattern 3: Type-Specific Configuration
Use case: Different types need different fields
Example: IF node conditions
// String operations
{
"name": "value2",
"displayOptions": {
"show": {
"conditions.string.0.operation": ["equals", "notEquals", "contains"]
}
}
}
// Unary operations (isEmpty) don't show value2
{
"displayOptions": {
"hide": {
"conditions.string.0.operation": ["isEmpty", "isNotEmpty"]
}
}
}
Pattern 4: Method-Specific Fields
Use case: HTTP methods have different options
Example: HTTP Request
// Query parameters (all methods can have)
{
"name": "queryParameters",
"displayOptions": {
"show": {
"sendQuery": [true]
}
}
}
// Body (only certain methods)
{
"name": "body",
"displayOptions": {
"show": {
"sendBody": [true],
"method": ["POST", "PUT", "PATCH", "DELETE"]
}
}
}
Using get_property_dependencies
Basic Usage
const deps = get_property_dependencies({
nodeType: "nodes-base.httpRequest"
});
Example Response
{
"nodeType": "n8n-nodes-base.httpRequest",
"dependencies": {
"body": {
"shows_when": {
"sendBody": [true],
"method": ["POST", "PUT", "PATCH", "DELETE"]
},
"required_when_shown": true
},
"queryParameters": {
"shows_when": {
"sendQuery": [true]
},
"required_when_shown": false
},
"headerParameters": {
"shows_when": {
"sendHeaders": [true]
},
"required_when_shown": false
}
}
}
When to Use
✅ Use when:
- Validation fails with "missing field" but you don't see that field
- A field appears/disappears unexpectedly
- You need to understand what controls field visibility
- Building dynamic configuration tools
❌ Don't use when:
- Simple configuration (use get_node_essentials)
- Just starting configuration
- Field requirements are obvious
Complex Dependency Examples
Example 1: HTTP Request Complete Flow
Scenario: Configuring POST with JSON body
Step 1: Set method
{
"method": "POST"
// → sendBody becomes visible
}
Step 2: Enable body
{
"method": "POST",
"sendBody": true
// → body field becomes visible AND required
}
Step 3: Configure body
{
"method": "POST",
"sendBody": true,
"body": {
"contentType": "json"
// → content field becomes visible AND required
}
}
Step 4: Add content
{
"method": "POST",
"sendBody": true,
"body": {
"contentType": "json",
"content": {
"name": "John",
"email": "john@example.com"
}
}
}
// ✅ Valid!
Dependency chain:
method=POST
→ sendBody visible
→ sendBody=true
→ body visible + required
→ body.contentType=json
→ body.content visible + required
Example 2: IF Node Operator Dependencies
Scenario: String comparison with different operators
Binary operator (equals):
{
"conditions": {
"string": [
{
"operation": "equals"
// → value1 required
// → value2 required
// → singleValue should NOT be set
}
]
}
}
Unary operator (isEmpty):
{
"conditions": {
"string": [
{
"operation": "isEmpty"
// → value1 required
// → value2 should NOT be set
// → singleValue should be true (auto-added)
}
]
}
}
Dependency table:
| Operator | value1 | value2 | singleValue |
|---|---|---|---|
| equals | Required | Required | false |
| notEquals | Required | Required | false |
| contains | Required | Required | false |
| isEmpty | Required | Hidden | true |
| isNotEmpty | Required | Hidden | true |
Example 3: Slack Operation Matrix
Scenario: Different Slack operations show different fields
// post message
{
"resource": "message",
"operation": "post"
// Shows: channel (required), text (required), attachments, blocks
}
// update message
{
"resource": "message",
"operation": "update"
// Shows: messageId (required), text (required), channel (optional)
}
// delete message
{
"resource": "message",
"operation": "delete"
// Shows: messageId (required), channel (required)
// Hides: text, attachments, blocks
}
// get message
{
"resource": "message",
"operation": "get"
// Shows: messageId (required), channel (required)
// Hides: text, attachments, blocks
}
Field visibility matrix:
| Field | post | update | delete | get |
|---|---|---|---|---|
| channel | Required | Optional | Required | Required |
| text | Required | Required | Hidden | Hidden |
| messageId | Hidden | Required | Required | Required |
| attachments | Optional | Optional | Hidden | Hidden |
| blocks | Optional | Optional | Hidden | Hidden |
Nested Dependencies
What Are They?
Definition: Dependencies within object properties
Example: HTTP Request body.contentType controls body.content structure
{
"body": {
"contentType": "json",
// → content expects JSON object
"content": {
"key": "value"
}
}
}
{
"body": {
"contentType": "form-data",
// → content expects form fields array
"content": [
{
"name": "field1",
"value": "value1"
}
]
}
}
How to Handle
Strategy: Configure parent first, then children
// Step 1: Parent
{
"body": {
"contentType": "json" // Set parent first
}
}
// Step 2: Children (structure determined by parent)
{
"body": {
"contentType": "json",
"content": { // JSON object format
"key": "value"
}
}
}
Auto-Sanitization and Dependencies
What Auto-Sanitization Fixes
Operator structure issues (IF/Switch nodes):
Example: singleValue property
// You configure (missing singleValue)
{
"type": "boolean",
"operation": "isEmpty"
// Missing singleValue
}
// Auto-sanitization adds it
{
"type": "boolean",
"operation": "isEmpty",
"singleValue": true // ✅ Added automatically
}
What It Doesn't Fix
Missing required fields:
// You configure (missing channel)
{
"resource": "message",
"operation": "post",
"text": "Hello"
// Missing required field: channel
}
// Auto-sanitization does NOT add
// You must add it yourself
{
"resource": "message",
"operation": "post",
"channel": "#general", // ← You must add
"text": "Hello"
}
Troubleshooting Dependencies
Problem 1: "Field X is required but not visible"
Error:
{
"type": "missing_required",
"property": "body",
"message": "body is required"
}
But you don't see body field in configuration!
Solution:
// Check dependencies
const deps = get_property_dependencies({
nodeType: "nodes-base.httpRequest"
});
// Find that body shows when sendBody=true
// Add sendBody
{
"method": "POST",
"sendBody": true, // ← Now body appears!
"body": {...}
}
Problem 2: "Field disappears when I change operation"
Scenario:
// Working configuration
{
"resource": "message",
"operation": "post",
"channel": "#general",
"text": "Hello"
}
// Change operation
{
"resource": "message",
"operation": "update", // Changed
"channel": "#general", // Still here
"text": "Updated" // Still here
// Missing: messageId (required for update!)
}
Validation error: "messageId is required"
Why: Different operation = different required fields
Solution:
// Check essentials for new operation
get_node_essentials({
nodeType: "nodes-base.slack"
});
// Configure for update operation
{
"resource": "message",
"operation": "update",
"messageId": "1234567890", // Required for update
"text": "Updated",
"channel": "#general" // Optional for update
}
Problem 3: "Validation passes but field doesn't save"
Scenario: Field hidden by dependencies after validation
Example:
// Configure
{
"method": "GET",
"sendBody": true, // ❌ GET doesn't support body
"body": {...} // This will be stripped
}
// After save
{
"method": "GET"
// body removed because method=GET hides it
}
Solution: Respect dependencies from the start
// Correct approach
get_property_dependencies({
nodeType: "nodes-base.httpRequest"
});
// See that body only shows for POST/PUT/PATCH/DELETE
// Use correct method
{
"method": "POST",
"sendBody": true,
"body": {...}
}
Advanced Patterns
Pattern 1: Conditional Required with Fallback
Example: Channel can be string OR expression
// Option 1: String
{
"channel": "#general"
}
// Option 2: Expression
{
"channel": "={{$json.channelName}}"
}
// Validation accepts both
Pattern 2: Mutually Exclusive Fields
Example: Use either ID or name, not both
// Use messageId
{
"messageId": "1234567890"
// name not needed
}
// OR use messageName
{
"messageName": "thread-name"
// messageId not needed
}
// Dependencies ensure only one is required
Pattern 3: Progressive Complexity
Example: Simple mode vs advanced mode
// Simple mode
{
"mode": "simple",
"text": "{{$json.message}}"
// Advanced fields hidden
}
// Advanced mode
{
"mode": "advanced",
"attachments": [...],
"blocks": [...],
"metadata": {...}
// Simple field hidden, advanced fields shown
}
Best Practices
✅ Do
-
Check dependencies when stuck
get_property_dependencies({nodeType: "..."}); -
Configure parent properties first
// First: method, resource, operation // Then: dependent fields -
Validate after changing operation
// Operation changed → requirements changed validate_node_operation({...}); -
Read validation errors for dependency hints
Error: "body required when sendBody=true" → Hint: Set sendBody=true to enable body
❌ Don't
-
Don't ignore dependency errors
// Error: "body not visible" → Check displayOptions -
Don't hardcode all possible fields
// Bad: Adding fields that will be hidden -
Don't assume operations are identical
// Each operation has unique requirements
Summary
Key Concepts:
displayOptionscontrol field visibilityshow= field appears when conditions matchhide= field disappears when conditions match- Multiple conditions = AND logic
- Multiple values = OR logic
Common Patterns:
- Boolean toggle (sendBody → body)
- Resource/operation cascade (different operations → different fields)
- Type-specific config (string vs boolean conditions)
- Method-specific fields (GET vs POST)
Troubleshooting:
- Field required but not visible → Check dependencies
- Field disappears after change → Operation changed requirements
- Field doesn't save → Hidden by dependencies
Tools:
get_property_dependencies- See dependency rulesget_node_essentials- See operation requirements- Validation errors - Hints about dependencies
Related Files:
- SKILL.md - Main configuration guide
- OPERATION_PATTERNS.md - Common patterns by node type