Documentation Index Fetch the complete documentation index at: https://mintlify.com/czlonkowski/n8n-skills/llms.txt
Use this file to discover all available pages before exploring further.
Node Configuration
Expert guidance for operation-aware node configuration with property dependencies.
Progressive disclosure principle: Start minimal, add complexity as needed. Use get_node({detail: "standard"}) first — it covers 95% of configuration needs with a ~1–2K token response. Only escalate to detail: "full" when standard detail is insufficient.
Core Concept: Operation-Aware Configuration
Not all fields are always required. Which fields are required depends on the operation selected.
// Slack: operation = "post" requires channel + text
{
resource : "message" ,
operation : "post" ,
channel : "#general" , // Required for post
text : "Hello!" // Required for post
}
// Slack: operation = "update" requires messageId, NOT channel
{
resource : "message" ,
operation : "update" ,
messageId : "123" , // Required for update (different!)
text : "Updated!"
// channel NOT required for update
}
// Slack: operation = "create" (channel) requires name, NOT text
{
resource : "channel" ,
operation : "create" ,
name : "new-channel" , // Required for channel create
isPrivate : false
// text NOT required at all for this operation
}
Key insight: Always re-check get_node when changing the resource or operation. Fields change.
Property Dependencies (displayOptions)
Fields appear and disappear based on the values of other fields. This is controlled by displayOptions rules.
// Example: body field in HTTP Request
{
name : "body" ,
displayOptions : {
show : {
sendBody : [ true ],
method : [ "POST" , "PUT" , "PATCH" ]
}
}
}
// Translation: "body" only appears when sendBody=true AND method is POST/PUT/PATCH
Common Dependency Chains
HTTP Request: POST with JSON body
// Full dependency chain:
// method="POST" → sendBody available
// sendBody=true → body required
// body.contentType="json" → body.content expected as JSON
{
method : "POST" ,
url : "https://api.example.com/create" ,
sendBody : true ,
body : {
contentType : "json" ,
content : {
name : "={{$json.body.name}}" ,
email : "={{$json.body.email}}"
}
}
}
HTTP Request: GET with query params
// sendQuery=true → queryParameters required
{
method : "GET" ,
url : "https://api.example.com/users" ,
authentication : "predefinedCredentialType" ,
nodeCredentialType : "httpHeaderAuth" ,
sendQuery : true ,
queryParameters : {
parameters : [
{ name: "limit" , value: "100" },
{ name: "offset" , value: "0" }
]
}
}
IF Node: string comparison (binary)
// Binary operator (equals, contains, etc.) → needs value1 + value2
// Auto-sanitization removes singleValue from binary operators
{
conditions : {
string : [
{
value1: "={{$json.status}}" ,
operation: "equals" ,
value2: "active" // Binary: needs both value1 AND value2
}
]
}
}
IF Node: empty check (unary)
// Unary operator (isEmpty, isNotEmpty) → needs only value1
// Auto-sanitization adds singleValue: true automatically
{
conditions : {
string : [
{
value1: "={{$json.email}}" ,
operation: "isEmpty"
// singleValue: true ← added automatically by auto-sanitization
// No value2 — unary operator checks single value
}
]
}
}
Postgres: different operations
// executeQuery → query required
{
operation : "executeQuery" ,
query : "SELECT * FROM users WHERE id = $1" ,
additionalFields : { queryParams : "={{$json.userId}}" }
}
// insert → table + columns required
{
operation : "insert" ,
table : "users" ,
columns : "id,name,email"
}
// update → table + updateKey required
{
operation : "update" ,
table : "users" ,
updateKey : "id"
}
get_node Detail Level Decision Tree
Starting a new node configuration?
└→ get_node({detail: "standard"}) ← Always start here
|
Does standard detail have what you need?
├ YES → Configure with it
└ NO → Looking for a specific field name?
├ YES → get_node({mode: "search_properties", propertyQuery: "auth"})
└ NO → get_node({detail: "full"}) ← Last resort only
Detail Level Tokens Use When minimal~200 Quick metadata only standard~1–2K Default — covers 95% of needs full~3–8K Complex debugging; complete schema
Configuration Workflow
Identify node type and operation
What service are you integrating? What action do you want to perform? // Goal: Post a message to Slack
// Node: nodes-base.slack
// Resource: message
// Operation: post
Get node info (standard detail)
get_node ({
nodeType: "nodes-base.slack" ,
includeExamples: true // Get real template configs
})
// Returns: operations, required fields, example configurations
Build minimal configuration
Start with only the required fields: {
resource : "message" ,
operation : "post" ,
channel : "#general" ,
text : "Hello!"
}
Validate
validate_node ({
nodeType: "nodes-base.slack" ,
config ,
profile: "runtime"
})
// Follow validation loop: fix errors, validate again (2–3 cycles is normal)
Search for specific properties if stuck
get_node ({
nodeType: "nodes-base.httpRequest" ,
mode: "search_properties" ,
propertyQuery: "auth" // Finds authentication-related properties
})
Add optional fields and validate again
Only add fields you actually need. Avoid over-configuring upfront.
AI Connection Types
When building AI workflows, connections use special sourceOutput types:
Connection Type sourceOutput ValueExample Node Language Model ai_languageModelOpenAI Chat Model Tool ai_toolHTTP Request Tool, Code Tool Memory ai_memoryWindow Buffer Memory Output Parser ai_outputParserStructured Output Parser Embedding ai_embeddingOpenAI Embeddings Vector Store ai_vectorStorePinecone, Qdrant Document ai_documentDefault Data Loader Text Splitter ai_textSplitterRecursive Character Splitter
// Connect a language model to the AI Agent
{
type : "addConnection" ,
source : "OpenAI Chat Model" ,
target : "AI Agent" ,
sourceOutput : "ai_languageModel"
}
// Connect multiple tools
{
type : "addConnection" ,
source : "HTTP Request Tool" ,
target : "AI Agent" ,
sourceOutput : "ai_tool"
}
Common Node Configuration Patterns
Resource/Operation Nodes
HTTP-Based Nodes
Database Nodes
Conditional Logic Nodes
Examples: Slack, Google Sheets, Airtable, NotionStructure: resource + operation determines all required fields. // Pattern
{
resource : "<entity>" , // What thing (message, channel, row...)
operation : "<action>" , // What to do (post, create, update...)
// ... operation-specific fields
}
// Always re-check get_node when changing resource or operation!
Examples: HTTP Request, Webhook// GET request — no body
{
method : "GET" ,
url : "https://api.example.com/users" ,
authentication : "predefinedCredentialType" ,
nodeCredentialType : "httpHeaderAuth"
}
// POST with JSON body
{
method : "POST" ,
url : "https://api.example.com/create" ,
authentication : "none" ,
sendBody : true , // Required to enable body!
body : {
contentType : "json" ,
content : { name : "John" , email : "john@example.com" }
}
}
Examples: Postgres, MySQL, MongoDB// Query
{
operation : "executeQuery" ,
query : "SELECT * FROM users WHERE status = 'active' LIMIT 100"
}
// Insert
{
operation : "insert" ,
table : "users" ,
columns : "name,email,created_at"
}
// Update with upsert
{
operation : "upsert" ,
table : "users" ,
conflictColumns : "email" ,
updateColumns : "name,updated_at"
}
Examples: IF, Switch// IF node: string comparison
{
conditions : {
string : [
{
value1: "={{$json.status}}" ,
operation: "equals" ,
value2: "active"
}
]
}
}
// IF node: number comparison
{
conditions : {
number : [
{
value1: "={{$json.score}}" ,
operation: "greaterThan" ,
value2: 50
}
]
}
}
Don’t manually add or remove singleValue — auto-sanitization handles this correctly on every save.
Configuration Anti-Patterns
Over-configuring upfront // ❌ Don't add every optional field
{
method : "GET" ,
url : "..." ,
sendQuery : false ,
sendHeaders : false ,
sendBody : false ,
timeout : 10000 ,
// ... 20 more optional fields
}
Start minimal instead // ✅ Start with only required fields
{
method : "GET" ,
url : "..." ,
authentication : "none"
}
// Add more only when validation asks for it
Copy configs without checking // ❌ Copy Slack post config for update
{
resource : "message" ,
operation : "update" , // Changed
channel : "#general" , // Wrong field for update!
text : "Updated"
}
Check requirements when switching // ✅ Check get_node after changing operation
get_node ({ nodeType: "nodes-base.slack" })
// See that update needs messageId, not channel
{
resource : "message" ,
operation : "update" ,
messageId : "12345678" , // Correct!
text : "Updated"
}
Best Practices
Practice Why Start with get_node({detail: "standard"}) Covers 95% of needs at 1–2K tokens Validate iteratively (2–3 cycles is normal) Validation reveals missing dependencies Use search_properties mode when stuck Finds fields by name efficiently Respect operation context Different operations ← different requirements Trust auto-sanitization Don’t manually manage singleValue Never jump straight to detail: "full" Try standard and search_properties first