Three practical workflows you can build in n8n today. No coding required, just clicking and configuring nodes.
Workflow 1: Webhook + Ollama Chat API
What it does: POST a question via webhook, get AI response from local Ollama.
Time: 5 minutes
Setup
-
Dashboard β New Workflow β Name: "Chat API"
-
Add Webhook node
- Authentication: None (test only)
- HTTP Method: POST
- Path:
/chat - Save
-
Add Ollama node after Webhook
- Base URL:
http://ollama:11434 - Model:
mistral - Prompt:
={{ $json.message }} - Save
- Base URL:
-
Add Respond to Webhook node
- Response Body:
{ "response": "={{ $json.response }}" }
- Response Body:
-
Activate workflow
Test
curl -X POST http://your-server:5678/webhook/chat \
-H "Content-Type: application/json" \
-d '{"message": "What is Docker in one sentence?"}'
Expected response:
{
"response": "Docker is a containerization platform that packages applications and their dependencies into isolated, portable containers that can run consistently across different environments."
}
Variation: Add Set node between Webhook and Ollama to format the prompt:
n8n Expression:
{{ "User question: " + $json.message + "\nAnswer concisely:" }}
Workflow 2: RSS Feed β AI Summary
What it does: Fetch RSS feed items hourly, summarize each with Ollama, save to file or email.
Time: 10 minutes
Setup
-
New Workflow β "RSS Summarizer"
-
Add Schedule node (trigger)
- Trigger type: Every hours
- Interval: 1
- Save
-
Add RSS Read node
- URL:
https://feeds.techcrunch.com/feed/ - Limit: 5 items
- Save
- URL:
-
Add Item Lists node
- Mode: "Split Out"
- Runs workflow for each RSS item
- Save
-
Add Ollama node
- Prompt:
Summarize this news article in 2 sentences: Title: {{ $json.title }} Description: {{ $json.description }} - Model:
mistral - Save
- Prompt:
-
Add Write Binary File node (to save summaries)
- File Name:
/tmp/summaries-{{ $now.format('YYYY-MM-DD') }}.txt - File Content:
{{ $json.title }} - {{ $json.response }} - Append: true
- Save
- File Name:
-
Activate
Test Run
Click "Test Workflow" to fetch and summarize one item immediately.
Variation: Replace Write Binary File with Email Send:
- To: [email protected]
- Subject: "Daily Tech Summary"
- Text:
{{ $json.title }}\n\n{{ $json.response }}
Workflow 3: Form Submission β Classification
What it does: Accept form submissions, classify text with Ollama, route to different handlers.
Time: 15 minutes
Setup
-
New Workflow β "Form Classifier"
-
Add Webhook node
- HTTP Method: POST
- Path:
/submit-form - Save
-
Add Ollama node
- Prompt:
Classify the following text as one of: bug_report, feature_request, question, feedback Text: {{ $json.text }} Reply with ONLY the category name. - Model:
mistral - Save
- Prompt:
-
Add Set node to clean response
- Set:
- category:
={{ $json.response.toLowerCase().trim() }}
- category:
- Save
- Set:
-
Add If node (conditional)
- Condition:
categorycontains "bug" - Save
- Condition:
-
TRUE path (bug branch):
- Add Email Send node
- To:
[email protected] - Subject: "New Bug Report: {{ $json.title }}"
- Text:
{{ $json.text }}
- To:
- Add Email Send node
-
FALSE path (other branches):
- Add Google Sheets node (or Write Binary File)
- Sheet: "Feedback"
- Action: "Append Row"
- Values:
[{{ $json.title }}, {{ $json.text }}, {{ $json.category }}]
- Add Google Sheets node (or Write Binary File)
-
Activate
Test
curl -X POST http://your-server:5678/webhook/submit-form \
-H "Content-Type: application/json" \
-d '{
"title": "Login button broken",
"text": "The login button does not work on mobile devices"
}'
Ollama should classify as "bug_report" and email should be sent to [email protected].
Key n8n Concepts
Expressions
Use {{ }} to access data:
{{ $json.field_name }} # From previous node
{{ $json.title }} # Specific field
{{ $json.0.name }} # Array element
{{ $now.format('YYYY-MM-DD') }} # Current date
{{ $env.MY_VAR }} # Environment variable
For operations, use = prefix:
={{ $json.count + 1 }} # Add 1
={{ $json.text.toUpperCase() }} # Uppercase
={{ $json.items.length }} # Array length
Node Chains
- Linear: Trigger β Node A β Node B β Node C
- Conditional: After If node, split into TRUE/FALSE paths
- Loop: Item Lists (split) β process each β merge
- Merge: Combine results from multiple paths back into one
Common Node Types
| Node | Purpose |
|---|---|
| Webhook | Accept HTTP requests |
| Schedule | Run on timer (hourly, daily, weekly) |
| Ollama | LLM requests |
| Email Send | Send email |
| Write Binary File | Save output to file |
| Google Sheets | Append/update rows |
| If | Conditional logic |
| Set | Transform data |
| Item Lists | Loop over arrays |
| HTTP Request | Call external APIs |
Error Handling
Every workflow can have an Error workflow:
- Create new workflow β Name: "Chat API Error Handler"
- Trigger: "Error in Workflow"
- Add Email Send:
- To:
[email protected] - Subject:
Workflow error: {{ $json.workflowName }} - Text:
{{ JSON.stringify($json.error, null, 2) }}
- To:
Link in main workflow:
- Settings β On error: Select error handler workflow
Performance Tips
Rate limiting (avoid Ollama overload):
- Add Wait node between workflows
- Set delay: 1-2 seconds per request
Caching (avoid repeated calls):
- Store Ollama responses in Google Sheets or database
- Check if request was processed before
Timeout (prevent hanging):
- Ollama node β Timeout: 30 seconds
- Webhook β Response timeout: 30 seconds
Common Issues
"Cannot connect to Ollama"
- Check:
docker exec ollama ollama serveis running - Verify URL:
http://ollama:11434(not localhost from within container)
Workflow never triggers on schedule
- Activate workflow (green toggle)
- Ensure Schedule node is set
- Check n8n logs:
docker logs n8n
Memory error with large feeds
- Reduce Limit in RSS Read node
- Add Wait between items (0.5 seconds)
Empty email body
- Use raw text instead of JSON:
{{ $json.response }} - Preview email before sending
Next Steps
- Combine all three: Schedule β RSS β Classify β Route
- Add database persistence (PostgreSQL, MongoDB)
- Connect to Slack for notifications
- Export workflow as JSON, share with team
- Set up error notifications
Checklist
- Ollama running with model available
- n8n accessible at http://your-server:5678
- Workflow 1 (Chat API) created and tested
- Workflow 2 (RSS Summarizer) scheduled and running
- Workflow 3 (Form Classifier) processing submissions
- All three workflows activated
- Error handlers configured
- Credentials tested in each Ollama node
- Sample test data verified
Workflow 4: Database-Driven Email Campaign
What it does: Store contacts in PostgreSQL, send personalized emails based on segments.
Time: 20 minutes
Setup
-
New Workflow β "Email Campaign"
-
Add Schedule node
- Trigger: Daily at 9 AM
- Timezone: UTC
- Save
-
Add PostgreSQL node
- Query:
SELECT id, email, first_name, segment FROM contacts WHERE segment = 'active' AND last_email < NOW() - INTERVAL '7 days' - Save
- Query:
-
Add Item Lists (split contacts)
- Mode: "Split Out"
-
Add Email node
- To:
{{ $json.email }} - Subject:
Hi {{ $json.first_name }}, exclusive offer inside - Body:
Dear {{ $json.first_name }}, We noticed you haven't heard from us in a while. Here's a special {{ $json.segment }} offer just for you. Best regards, The Team - Save
- To:
-
Add PostgreSQL node (update sent timestamp)
- Query:
UPDATE contacts SET last_email = NOW() WHERE id = {{ $json.id }}
- Query:
-
Activate
Test
Click "Test Workflow" β Should process contacts and send emails.
Workflow 5: Slack Notification Hub
What it does: Route different event types to different Slack channels with formatting.
Time: 15 minutes
Setup
-
New Workflow β "Slack Hub"
-
Add Webhook node
- Path:
/slack-notify
- Path:
-
Add Set node (normalize event)
- Set:
- event_type:
={{ $json.type.toLowerCase() }} - urgency:
={{ $json.priority || 'normal' }} - message:
={{ $json.text }}
- event_type:
- Set:
-
Add If node (route by event type)
- Condition:
event_typeequals "alert"
- Condition:
-
TRUE path (high-priority alerts):
- Add Slack node
- Channel:
#alerts - Message:
π¨ URGENT: {{ $json.message }} Priority: {{ $json.urgency }} - Icon: β οΈ
- Channel:
- Add Slack node
-
FALSE path (other events):
- Add another If node
- Condition:
event_typeequals "update"
- Condition:
- Add another If node
-
TRUE branch:
- Slack node β Channel:
#updates - Message:
π’ {{ $json.message }}
- Slack node β Channel:
-
FALSE branch (default):
- Slack node β Channel:
#general - Message:
{{ $json.message }}
- Slack node β Channel:
-
Add Respond to Webhook at end
- Response:
{"status": "sent"}
- Response:
-
Activate
Test
curl -X POST http://localhost:5678/webhook/slack-notify \
-H "Content-Type: application/json" \
-d '{
"type": "alert",
"priority": "high",
"text": "Database connection failed"
}'
Message should appear in #alerts with π¨ emoji.
Workflow 6: Multi-Step Data Pipeline
What it does: Extract CSV β Transform β Validate β Load to Sheets.
Time: 25 minutes
Setup
-
New Workflow β "ETL Pipeline"
-
Add Webhook node
- Path:
/upload-csv - Accept: File upload
- Path:
-
Add CSV to JSON node
- Input:
{{ $json.file }}
- Input:
-
Add Item Lists (process each row)
-
Add Set node (transform)
- Clean:
={{ $json.name.trim().toUpperCase() }} - Email:
={{ $json.email.toLowerCase() }} - Age:
={{ parseInt($json.age) }}
- Clean:
-
Add If node (validate)
- Condition: Email matches regex
\S+@\S+\.\S+
- Condition: Email matches regex
-
TRUE path (valid):
- Add Google Sheets node
- Append Row:
[{{ $json.clean }}, {{ $json.email }}, {{ $json.age }}]
- Append Row:
- Add Google Sheets node
-
FALSE path (invalid):
- Add Write Binary File node
- Append to:
/tmp/invalid-records.txt - Content:
{{ JSON.stringify($json) }}\n
- Append to:
- Add Write Binary File node
-
After both paths, Merge node
- Join: Combine results
-
Add final Respond to Webhook
- Response:
{"processed": {{ $node.merge.data.length }}, "errors": {{ $node.merge.errors.length }}}
- Response:
-
Activate
Test
Upload CSV:
name,email,age
John,[email protected],30
jane,invalid-email,25
Results:
- John β Google Sheets
- Jane β
/tmp/invalid-records.txt
Common n8n Patterns
Loop with Accumulation
Process items and collect results:
Item Lists (split)
β Process item
β Accumulate in array
Merge
β Final array with all results
Conditional Retry
Try node
β On error: Wait 5s
β Retry same node
β If still errors: Alert admin
Rate Limiting
Process item
β Wait 1 second
β Next item
Prevents API throttling.
Performance Optimization
1. Batch Operations
Slow:
For each contact:
β Call API
β Process response
(1000 contacts = 1000 API calls)
Fast:
Collect 100 contacts
β Call batch API (1 call)
β Process 100 responses
(10 API calls total)
2. Caching Results
Check Cache (Set node with object)
β If not found: Fetch from API
β If found: Use cached value
3. Parallel Processing
Split items into 5 groups
β Process each group in parallel
β Merge results
(5x faster for I/O-bound tasks)
Debugging Workflows
1. Visual Debugger
Click Test Workflow β See each node's output:
Node 1 output: β
{ "contacts": [...] }
Node 2 output: β
{ "filtered": [...] }
Node 3 output: β ERROR
"API rate limited"
2. Logging
Add Log node to inspect data at any point:
Before processing:
{{ JSON.stringify($json, null, 2) }}
Appears in n8n logs.
3. Error Handling per Node
Click node β Error:
- Handle with: Wait 10s, then continue
- Or: Stop workflow
Webhook Security
Basic Auth
Webhook node settings:
Authentication: Basic Auth
Username: admin
Password: (generated)
Test with:
curl -u admin:password http://localhost:5678/webhook/path
IP Allowlist
Webhook settings:
Allowed IPs: 192.168.1.100, 10.0.0.0/8
Only those IPs can trigger.
Exporting & Sharing Workflows
Export JSON
Workflow β Menu β Download:
{
"nodes": [...],
"connections": [...],
"metadata": {...}
}
Share this file with team.
Import
New Workflow β Load from File β Select JSON
Entire workflow imported (nodes, connections, settings).
Moving Workflows to Production
1. Test Thoroughly
- Mock external APIs
- Test error paths
- Verify with real data sample
2. Monitor Execution
- Set error handler (email on failure)
- Log important events
- Track execution times
3. Credentials Management
- Never hardcode API keys in workflows
- Use n8n Credentials system
- Rotate keys quarterly
4. Versioning
- Keep backup of JSON exports
- Track changes in Git
- Document updates
Advanced Scheduling
Cron Expressions
0 9 * * 1-5 = Every weekday at 9 AM
0 0 1 * * = First of every month
0 */6 * * * = Every 6 hours
Conditional Scheduling
Schedule node every hour
β If certain conditions met: Continue workflow
β Else: Skip this run
