How to structure an n8n custom node with multiple actions under one main node?

I’m working on a custom n8n node for my company. Right now I have two separate action nodes (authenticate and upload file) that show up when I search for the company name in the node panel. But I want to combine them under one main node, similar to how the S3 node works.

Currently, when I select either action, I get a dropdown to choose between them. What I’m aiming for is a single company node with multiple actions inside it, rather than separate nodes for each action.

I’ve tried setting up my main.node.ts file with an Operation property that includes both actions, and I’ve listed both action files in my package.json. But this approach still results in separate core nodes.

Here’s a simplified version of my current setup:

export class CompanyNode implements INodeType {
  description: INodeTypeDescription = {
    displayName: 'CompanyActions',
    name: 'companyActions',
    properties: [
      {
        displayName: 'Action',
        name: 'action',
        type: 'options',
        options: [
          { name: 'Authenticate', value: 'auth' },
          { name: 'Upload File', value: 'upload' }
        ],
        default: 'auth'
      },
      // Other properties...
    ]
  };
}

Any ideas on how to structure this correctly to achieve a single main node with multiple actions?

From my experience with n8n custom nodes, it’s best to build your node around resources and operations instead of separate actions. A single node can first let users select a resource like Authentication or File. Then, based on that selection, they choose the operation such as Authenticate for authentication or Upload for file handling. This resource-oriented design creates a more intuitive interface and makes it easier to add operations later. I refined my approach through trial and error, and the unified setup turned out to be much cleaner in the end.

hey, have u tried using a resource-based approach? instead of separate actions, make one main node with different resources. then u can have operations for each resource. it’ll look more like the s3 node ur aiming for.

somethin like this in ur main.ts:

resource: [authentication, file]
operation (for authentication): [authenticate]
operation (for file): [upload]

this way everything’s under one node. hope that helps!

To structure your custom n8n node with multiple actions under one main node, you’ll need to modify your approach slightly. Instead of separate action nodes, create a single node with resource and operation properties. This allows users to select different actions within the same node.

Here’s a basic structure to achieve this:

export class CompanyNode implements INodeType {
  description: INodeTypeDescription = {
    displayName: 'Company',
    name: 'company',
    icon: 'file:company.svg',
    group: ['transform'],
    version: 1,
    description: 'Interact with Company API',
    defaults: {
      name: 'Company',
    },
    inputs: ['main'],
    outputs: ['main'],
    properties: [
      {
        displayName: 'Resource',
        name: 'resource',
        type: 'options',
        options: [
          {
            name: 'Authentication',
            value: 'authentication',
          },
          {
            name: 'File',
            value: 'file',
          },
        ],
        default: 'authentication',
        description: 'Resource to use',
      },
      {
        displayName: 'Operation',
        name: 'operation',
        type: 'options',
        displayOptions: {
          show: {
            resource: [
              'authentication',
            ],
          },
        },
        options: [
          {
            name: 'Authenticate',
            value: 'authenticate',
            description: 'Authenticate with the API',
          },
        ],
        default: 'authenticate',
        description: 'Operation to perform',
      },
      {
        displayName: 'Operation',
        name: 'operation',
        type: 'options',
        displayOptions: {
          show: {
            resource: [
              'file',
            ],
          },
        },
        options: [
          {
            name: 'Upload',
            value: 'upload',
            description: 'Upload a file',
          },
        ],
        default: 'upload',
        description: 'Operation to perform',
      },
    ],
  };

  async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
    // Implementation details here
  }
}

This structure creates a single ‘Company’ node with different resources and operations, similar to the S3 node you mentioned. Users can then select the desired action within the node interface.