2026-06-07
Building Custom n8n Nodes: Create Your Own Integration in 30 Minutes
Complete guide to building custom n8n nodes. From the n8n node dev CLI to publishing on npm. Covers: node structure, credential management, API integration, TypeScript patterns, testing, and publishing. Build integrations for any internal or public API.
Building Custom n8n Nodes: Create Your Own Integration in 30 Minutes
n8n has 400+ native nodes. But your company has internal APIs, your favorite SaaS tool doesn't have a node yet, or you need a custom integration nobody else would build. That's when you build your own node.
When to Build a Custom Node
- Your company has an internal API used across multiple workflows
- A SaaS tool you love has no n8n node (but has a REST API)
- You need specialized functionality (custom encryption, proprietary protocol)
- You want to contribute back to n8n's open-source ecosystem
For one-off API calls in a single workflow, use the HTTP Request node. Build a custom node when you'll reuse it across many workflows.
Quick Start: n8n Node Dev CLI
n8n provides a scaffolding tool:
```bash npm install -g n8n-node-dev n8n-node-dev new ```
This prompts for:
- Node name (e.g., "AcmeCRM")
- Description
- Package name (npm-compatible)
It generates:
``` acme-crm/ ├── nodes/ │ └── AcmeCRM/ │ ├── AcmeCRM.node.ts # Main node logic │ ├── AcmeCRM.node.json # Node metadata │ └── AcmeCRMApi.ts # API wrapper ├── credentials/ │ └── AcmeCRMApi.credentials.ts # Auth handling └── package.json ```
Node Structure
The Node JSON (Metadata)
```json { "node": "n8n-nodes-base.acmeCrm", "nodeVersion": "1.0", "codexVersion": "1.0", "categories": ["Communication"], "resources": { "credentialDocumentation": [{"url": "https://docs.acmecrm.com/api"}], "primaryDocumentation": [{"url": "https://docs.acmecrm.com/api"}] } } ```
The Node TypeScript (Logic)
```typescript import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
export class AcmeCrm implements INodeType { description: INodeTypeDescription = { displayName: 'Acme CRM', name: 'acmeCrm', group: ['transform'], version: 1, description: 'Interact with Acme CRM API', defaults: { name: 'Acme CRM' }, inputs: ['main'], outputs: ['main'], credentials: [{ name: 'acmeCrmApi', required: true }], properties: [ // Operation selector { displayName: 'Operation', name: 'operation', type: 'options', options: [ { name: 'Create Contact', value: 'createContact' }, { name: 'Get Contact', value: 'getContact' }, { name: 'List Contacts', value: 'listContacts' }, ], default: 'createContact', }, // Fields (shown based on operation) { displayName: 'Email', name: 'email', type: 'string', default: '', required: true, displayOptions: { show: { operation: ['createContact'] } }, }, { displayName: 'Name', name: 'name', type: 'string', default: '', displayOptions: { show: { operation: ['createContact'] } }, }, ], };
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { const items = this.getInputData(); const returnData: INodeExecutionData[] = []; const credentials = await this.getCredentials('acmeCrmApi');
for (let i = 0; i < items.length; i++) {
const operation = this.getNodeParameter('operation', i) as string;
if (operation === 'createContact') {
const email = this.getNodeParameter('email', i) as string;
const name = this.getNodeParameter('name', i) as string;
const response = await this.helpers.httpRequest({
method: 'POST',
url: 'https://api.acmecrm.com/v1/contacts',
headers: {
Authorization: `Bearer ${credentials.apiKey}`,
'Content-Type': 'application/json',
},
body: { email, name },
});
returnData.push({ json: response });
}
}
return [returnData];
} } ```
The Credentials File
```typescript import { ICredentialType, INodeProperties } from 'n8n-workflow';
export class AcmeCrmApi implements ICredentialType { name = 'acmeCrmApi'; displayName = 'Acme CRM API'; properties: INodeProperties[] = [ { displayName: 'API Key', name: 'apiKey', type: 'string', default: '', typeOptions: { password: true }, // Masks the field }, ]; } ```
Installing Your Custom Node
Method 1: NPM Package (Recommended for Teams)
```bash
In your n8n directory
npm install @yourcompany/n8n-nodes-acme-crm ```
Set the environment variable:
```yaml environment:
- N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/node_modules/@yourcompany ```
Method 2: Local Development
```yaml volumes:
- ~/.n8n/custom-nodes:/home/node/.n8n/custom environment:
- N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom ```
Testing Custom Nodes
n8n-node-dev includes a test runner:
```typescript // AcmeCRM.test.ts import { testWorkflow } from 'n8n-node-dev';
const workflow = { nodes: [ { id: 'manual-1', name: 'Manual', type: 'n8n-nodes-base.manualTrigger', position: [250, 300] }, { id: 'acme-1', name: 'Acme CRM', type: 'n8n-nodes-base.acmeCrm', position: [450, 300], parameters: { operation: 'createContact', email: 'test@example.com', name: 'Test User' } } ], connections: { 'Manual': { main: [[{ node: 'Acme CRM', type: 'main', index: 0 }]] } } };
testWorkflow(workflow, { credentials: { acmeCrmApi: { apiKey: 'test-key' } } }); ```
Publishing to npm
```bash npm login npm publish --access public ```
n8n's community node registry picks it up automatically. Others can install and use your node.
When NOT to Build a Custom Node
- One-off API call → Use the HTTP Request node
- Rapidly changing API → HTTP Request node is easier to update than rebuilding a node
- Simple webhook → Generic Webhook node works
Build custom nodes for reuse, not one-offs. The HTTP Request node handles the 80% case.
Start with FlowForge templates to see how professional workflows are structured — then extend with custom nodes where needed. Browse templates →
Related n8n Templates
These pre-built n8n templates complement what you just read. Import and run in minutes.
Data
Web Scraper → Google Sheets Archive
Scrape any website on a schedule and automatically append the data to Google Sheets. Track competitor prices, job listings, or news headlines.
Utility
Weather API → SMS Severe Weather Alert
Monitor weather conditions for any location and automatically send SMS alerts when severe weather is forecast. Great for construction, events, or farming.
Sales
Customer Feedback → Sentiment Analysis → Slack
Analyze customer feedback sentiment automatically and route positive/negative responses to the right Slack channels. Positive → marketing. Negative → urgent support.
Related Articles
More in-depth guides and comparisons to level up your n8n skills.
Ready to automate?
Browse 25+ production-ready n8n templates. Import, configure, and run — all in under 10 minutes.
Browse Templates