# How to Create Custom Nodes in n8n: A Complete Implementation Guide

> Learn how to create custom nodes in n8n with this comprehensive guide. Implement custom logic and extend n8n's capabilities by building your own nodes.

- Repository: [n8n - Workflow Automation/n8n](https://github.com/n8n-io/n8n)
- Tags: how-to-guide
- Published: 2026-02-24

---

**To create custom nodes in n8n, you build a TypeScript class implementing the `IExecuteFunctions` interface with a static `description` object for metadata, then place the compiled module in the directory specified by the `customNodesPath` instance setting (default `~/.n8n/custom`).**

n8n's extensible architecture allows developers to add custom nodes that integrate seamlessly into the visual workflow editor alongside built-in integrations. These custom nodes are standard Node.js modules that follow n8n's node interface conventions and are automatically discovered at runtime. When you create custom nodes in n8n, you enable direct integration of proprietary APIs, internal services, or specialized business logic into your automation workflows.

## Understanding Custom Node Discovery

n8n loads node definitions from two distinct sources during startup. Built-in nodes reside in `packages/nodes-base`, while custom nodes are loaded from the file system path defined by the `customNodesPath` instance setting. According to the source code in [`packages/core/src/instance-settings/instance-settings.ts`](https://github.com/n8n-io/n8n/blob/main/packages/core/src/instance-settings/instance-settings.ts), this path defaults to `~/.n8n/custom` but can be overridden via the `N8N_CUSTOM_NODES_PATH` environment variable or configured in the UI under *Instance Settings → Custom Nodes Path*.

The loading mechanism is handled by [`packages/core/src/nodes-loader/directory-loader.ts`](https://github.com/n8n-io/n8n/blob/main/packages/core/src/nodes-loader/directory-loader.ts), which scans the designated directory and registers each discovered node and credential. The CLI helper that resolves these paths and initializes the runtime is located in [`packages/cli/src/load-nodes-and-credentials.ts`](https://github.com/n8n-io/n8n/blob/main/packages/cli/src/load-nodes-and-credentials.ts).

## Step 1: Scaffold the Node Structure

Begin by creating a new TypeScript file that exports a class implementing the required n8n interfaces. The official scaffolding guide in `packages/@n8n/create-node/README.md` provides templates and best practices for node development.

Your node file must export a class that implements execution functions. The minimal structure requires:

- A class implementing `IExecuteFunctions`
- A static `description` object defining metadata, UI properties, and connection points
- An `execute` method containing the runtime logic

## Step 2: Implement the Node Class and Description

The static `description` object defines how your node appears in the editor, including its display name, icon, inputs, outputs, and configurable properties. The `execute` method receives the runtime context and returns an array of execution data.

The following example demonstrates a basic custom node structure based on the templates in `packages/@n8n/create-node`:

```typescript
// packages/@n8n/create-node/templates/MyCustomNode.node.ts
import {
    IExecuteFunctions,
} from 'n8n-workflow';

export class MyCustomNode implements IExecuteFunctions {
    // Static description used by the UI
    static description = {
        displayName: 'My Custom Node',
        name: 'myCustomNode',
        group: ['transform'],
        version: 1,
        description: 'Fetches data from My API',
        defaults: {
            name: 'My Custom Node',
        },
        inputs: ['main'],
        outputs: ['main'],
        properties: [
            {
                displayName: 'Endpoint',
                name: 'endpoint',
                type: 'string',
                default: '',
                required: true,
            },
        ],
    };

    async execute(this: IExecuteFunctions): Promise<any[]> {
        const endpoint = this.getNodeParameter('endpoint', 0) as string;
        const response = await this.helpers.request({
            method: 'GET',
            uri: endpoint,
            json: true,
        });
        return this.prepareOutputData([{ json: response }]);
    }
}

```

## Step 3: Configure Credentials (Optional)

If your custom node requires authentication, create a matching credentials class in the same custom nodes directory. Define the credential properties and reference them in your node's `description.credentials` array. The credential definition follows the same pattern as built-in nodes found in `packages/nodes-base`.

## Step 4: Deploy to the Custom Nodes Directory

Place the compiled node file (or the entire npm package) into the custom nodes directory. By default, n8n watches `~/.n8n/custom/`, but you can configure this via the `N8N_CUSTOM_NODES_PATH` environment variable as implemented in [`packages/core/src/instance-settings/instance-settings.ts`](https://github.com/n8n-io/n8n/blob/main/packages/core/src/instance-settings/instance-settings.ts).

Organize your files using the following structure:

```bash
mkdir -p ~/.n8n/custom/MyCustomNode
cp dist/MyCustomNode.node.js ~/.n8n/custom/MyCustomNode/

```

For npm packages, n8n resolves modules from `node_modules` when the package name begins with `n8n-nodes-`, or when you explicitly add the package path to the custom nodes folder.

## Step 5: Restart or Enable Hot-Reload

After deployment, restart the n8n instance to load the new node. For development workflows, enable hot-reload by setting the environment variable `N8N_HOT_RELOAD=true` before starting n8n. This feature is exercised in the test suite at [`packages/core/src/nodes-loader/__tests__/directory-loader.test.ts`](https://github.com/n8n-io/n8n/blob/main/packages/core/src/nodes-loader/__tests__/directory-loader.test.ts), allowing automatic detection of file changes without manual restarts.

```bash
export N8N_HOT_RELOAD=true
n8n start

```

## Packaging Custom Nodes for Distribution

To distribute your custom node, package it as an npm module with the `n8n-nodes-` prefix. This naming convention allows n8n to automatically resolve the package from `node_modules`. Include the compiled JavaScript, TypeScript definitions, and a [`package.json`](https://github.com/n8n-io/n8n/blob/main/package.json) that declares the node files. Users can then install your package into their custom nodes directory or alongside their n8n installation.

## Summary

- **Custom nodes** are Node.js modules implementing `IExecuteFunctions` with a static `description` object that defines UI metadata and execution logic.
- n8n discovers custom nodes from the path defined in `customNodesPath` (default `~/.n8n/custom`), handled by [`packages/core/src/nodes-loader/directory-loader.ts`](https://github.com/n8n-io/n8n/blob/main/packages/core/src/nodes-loader/directory-loader.ts).
- Place compiled node files or npm packages in the custom directory, then restart n8n or enable `N8N_HOT_RELOAD=true` for automatic reloading during development.
- Optional credentials are implemented as separate classes in the same directory and referenced via the `description.credentials` property.
- For distribution, publish npm packages prefixed with `n8n-nodes-` to enable automatic resolution from `node_modules`.

## Frequently Asked Questions

### Where does n8n look for custom nodes?

n8n searches for custom nodes in the directory specified by the `customNodesPath` instance setting, which defaults to `~/.n8n/custom/` as defined in [`packages/core/src/instance-settings/instance-settings.ts`](https://github.com/n8n-io/n8n/blob/main/packages/core/src/instance-settings/instance-settings.ts). You can override this location using the `N8N_CUSTOM_NODES_PATH` environment variable or through the Instance Settings UI.

### What is the N8N_CUSTOM_NODES_PATH environment variable?

`N8N_CUSTOM_NODES_PATH` is an environment variable that specifies the absolute file system path where n8n should scan for user-provided nodes and credentials. When set, it overrides the default `~/.n8n/custom/` location processed by [`packages/core/src/nodes-loader/directory-loader.ts`](https://github.com/n8n-io/n8n/blob/main/packages/core/src/nodes-loader/directory-loader.ts).

### How do I debug a custom node during development?

Enable hot-reload by setting `N8N_HOT_RELOAD=true` before starting n8n, which allows the runtime to detect file changes in the custom nodes directory without requiring a full restart. This functionality is tested in [`packages/core/src/nodes-loader/__tests__/directory-loader.test.ts`](https://github.com/n8n-io/n8n/blob/main/packages/core/src/nodes-loader/__tests__/directory-loader.test.ts). You can also add `console.log` statements in the `execute` method or use the VS Code debugger attached to the n8n Node.js process.

### Can I publish custom nodes as npm packages?

Yes, you can publish custom nodes as standard npm packages. Name your package with the `n8n-nodes-` prefix so n8n automatically discovers it in `node_modules`, or manually place the package contents in your configured custom nodes directory. Ensure your [`package.json`](https://github.com/n8n-io/n8n/blob/main/package.json) correctly points to the compiled node files.