How to add a custom code node on n8n
Clone the n8n-nodes-starter template, create your TypeScript node file with INodeType interface, build with npm run build, then copy dist/ to ~/.n8n/custom/ and restart n8n. For Docker, mount the dist/ folder or build a custom image. Test by searching for your node name in the + panel.
Prerequisites
- Node.js v14+ and npm installed
- n8n self-hosted instance (local or Docker)
- Git for cloning repositories
- Basic TypeScript knowledge
- Access to n8n's ~/.n8n/custom/ directory
Step-by-Step Instructions
Clone n8n Nodes Starter Repository
git clone https://github.com/n8n-io/n8n-nodes-starter then cd n8n-nodes-starter. This provides boilerplate package.json, tsconfig.json, and node examples for quick setup.Install Dependencies
npm install to fetch TypeScript, n8n-workflow, and dev dependencies. Edit package.json to set "name": "n8n-nodes-mycustom" (prefix with n8n-nodes-), version, and scripts like "build": "tsc" and "dev": "tsc --watch".Create Your Node File
import { IExecuteFunctions } from 'n8n-core';
import { INodeType, INodeTypeDescription } from 'n8n-workflow';
export class MyCustomNode implements INodeType {
description: INodeTypeDescription = {
displayName: 'My Custom Node',
name: 'myCustomNode',
group: ['transform'],
version: 1,
description: 'Reverses input string',
defaults: { name: 'My Custom Node', color: '#1F8EB2' },
inputs: ['main'],
outputs: ['main'],
properties: [{
displayName: 'String to Reverse',
name: 'stringToReverse',
type: 'string',
default: '',
placeholder: 'Enter string'
}]
};
async execute(this: IExecuteFunctions) {
const items = this.getInputData();
const returnData = [];
const stringToReverse = this.getNodeParameter('stringToReverse', 0) as string;
returnData.push({ json: { reversed: stringToReverse.split('').reverse().join('') } });
return this.prepareOutputData(returnData);
}
} Save as nodes/MyCustomNode/MyCustomNode.node.ts. Update index.ts to export the class.Configure TypeScript
tsconfig.json has "outDir": "./dist", "target": "ES2019", "module": "CommonJS", and includes your node files. This compiles TS to JS in /dist/.Build the Node Package
npm run build to compile TypeScript to JavaScript in the dist/ folder. Verify dist/node/ and dist/credentials/ (if any) contain your files.Set Up Custom Directory in n8n
~/.n8n/custom/ if missing. Copy dist/node/ and dist/credentials/ into it, then cd ~/.n8n/custom/, run npm init -y, and npm install.Restart n8n
docker restart n8n or kill/restart local process). Open n8n at http://localhost:5678, create a new workflow, click +, and search for 'My Custom Node'.Docker Deployment (Production)
FROM n8nio/n8n:latest
USER root
COPY ./dist /home/node/.n8n/custom/
USER node Build custom image with your docker-compose.yml mounting ./dist:/home/node/.n8n/custom/node_modules/n8n-nodes-mycustom. Match n8n version.Test and Debug
docker logs n8n for module resolution issues.Document and Enhance
description object. Modularize with helpers and constants for complex logic.Common Issues & Troubleshooting
Node not visible in + panel (search yields nothing)
Create ~/.n8n/custom/, cd into it, npm init -y, copy dist/node/ and dist/credentials/, run npm install, restart n8n.
ENOENT: no such file or directory or module resolution fails in logs
Verify dist/ compiled correctly, run npm install in ~/.n8n/custom/, check paths, restart n8n, and inspect docker logs.
Node fails to execute (runtime errors)
Ensure async execute uses getInputData() and prepareOutputData(), match n8n-workflow version, rebuild with npm run build.
Changes not reflecting after edits
Rebuild with npm run build, recopy to custom/, run npm install, restart n8n, or use npm link for dev.
Docker: Node not found in container
Mount dist/ correctly in docker-compose.yml as /home/node/.n8n/custom/node_modules/<package-name>, rebuild image.