I run n8n on a small rack at home
I run n8n on a small rack at home. It handles the boring parts, saves time, and keeps the data tidy. The useful bit here is lead enrichment, not a tidy theory of automation.
Getting started with n8n workflows
Overview of n8n
n8n is a node-based automation tool. It takes a trigger, runs nodes in sequence, and can call APIs, transform data, and write to databases. It runs well on modest hardware. I self-host it in a homelab because I keep credentials and traffic local. n8n workflows are JSON files, so they fit nicely in GitHub for version control and rollback.
Setting up the environment
I deploy n8n with Docker Compose on an Intel NUC or something similar. Use Postgres for persistence when the workflows matter. A minimal service looks like this:
image: n8nio/n8n
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- N8N_PORT=5678
ports:
- "5678:5678"
volumes:
- ./n8n:/home/node/.n8n
Run it behind Caddy or a Cloudflare Tunnel if you need secure external webhooks. Keep credentials out of workflow JSON, and put API keys in environment variables or in n8n credentials. I pin images to stable tags so updates do not surprise me later.
Creating the first workflow
I start small. A repeatable lead enrichment flow looks like this:
- Webhook node receives a form post.
- SplitInBatches node limits parallel calls.
- HTTP Request node calls an enrichment API.
- Function node maps fields.
- Postgres node inserts or updates the lead.
- Notification node sends a message to a Slack or Matrix room.
Export the workflow as JSON. Commit it to a GitHub repo with a short runbook that says how to restore it and which environment variables it needs.
Common problems
Rate limits and duplicate records are the two biggest headaches.
- Rate limits: set batch size to 1 or 2, and add a Wait node between requests. Use retry on HTTP 429 with exponential backoff in a Function node.
- Duplicates: query by a canonical key, like email or domain, before insert. Use Postgres upsert.
- Credential leakage: keep credentials in n8n credentials or environment variables, not in exported JSON.
- Timezones and timestamps: store timestamps in UTC in the database; convert to local time only for display.
Workflow design
Name nodes clearly. Use short, descriptive labels like enrich.company rather than node12. Keep most logic in small, focused workflows. Chain workflows by webhook rather than one giant graph; that makes testing and retries less painful. Make workflows idempotent so replays do not double-insert. Version workflows in GitHub, and tag releases when you push changes live.
Practical applications of n8n for lead enrichment
Integrating with CRM systems
Connect n8n to CRMs like HubSpot, Pipedrive, or a self-hosted Postgres-backed CRM. The pattern I use is:
- Inbound lead -> dedupe -> enrich -> map fields -> push to CRM.
Map fields in a Function node so field changes are a single edit in code. For HubSpot and similar, call the CRM API in a single HTTP Request node. Respect rate limits by checking headers on responses, and back off when limits are close.
Automating data collection from different sources
Lead data rarely comes from one place. Common sources I collect from in a homelab:
- Webform webhooks from Typeform or native forms.
- Google Sheets exports for manual imports.
- RSS or job boards scraped with HTTP Request plus an HTML Extract node.
- Email parsing with a mail reader node or a small script that posts to a webhook.
Cache results in a local Postgres table. That avoids repeated enrichment calls and keeps costs down for paid APIs.
Improving lead data with third-party APIs
Use enrichment APIs to add company size, tech stack, and role. Common endpoints return JSON you can map directly. Keep a local TTL cache for each enriched domain. Example strategy:
- If the domain was seen within 30 days, use cached data.
- Otherwise call the enrichment API, then store the response and timestamp.
Watch for quota costs. Set daily caps in the workflow with a simple counter table in Postgres. That stops surprise bills.
Examples of working workflows
Example 1: Website form to CRM
- Webhook -> validate email -> dedupe in Postgres -> enrichment API -> upsert into HubSpot -> send team notification.
This flow uses SplitInBatches size 1 for enrichment and a 2-second Wait between API calls. It processes 5,000 leads a month without hitting most free-tier limits.
Example 2: Content lead scoring
- Scrape feed -> extract company domain -> enrichment API -> use a small OpenAI prompt to score intent -> push high-score leads into a sales queue.
Store scores and reasons in a JSON column. That makes the decision trail easier to follow and cuts down the arguments about why a lead ended up in the queue.
Testing and troubleshooting
Test one node at a time with Execute Node. Use small batches. For API-heavy nodes, mock responses with a local mock server or a recorded sample. Log full payloads to a test Postgres table. Set N8N_LOG_LEVEL=debug for short test runs, then switch back to info for production. If something breaks, revert to the last tagged release in GitHub and follow the restore steps in the runbook.
I still end up with a better result if I keep it small, keep workflows modular, protect credentials, and cache enrichment results locally. It is less glamorous, which is normally a good sign.




