# Neo Plugin Architecture: How to Extend Node Functionality with Custom Plugins

> Explore the Neo plugin architecture to extend node functionality effortlessly. Learn how to build custom plugins using the reflection-based framework and abstract Plugin class.

- Repository: [The Neo Project/neo](https://github.com/neo-project/neo)
- Tags: how-to-guide
- Published: 2026-03-08

---

**The Neo plugin architecture is a lightweight, reflection-based framework that automatically discovers DLLs from a `Plugins` folder and manages their lifecycle through the abstract `Plugin` base class, enabling developers to extend node functionality without modifying core blockchain code.**

The neo-project/neo repository implements a modular plugin system designed for runtime extensibility. Understanding the Neo plugin architecture is essential for implementing custom consensus rules, monitoring agents, or RPC extensions while isolating failures through configurable exception policies.

## Core Components of the Plugin Framework

The architecture centers on the `Neo.Plugins` namespace, where the base `Plugin` class orchestrates discovery, registration, and inter-plugin communication.

### The Plugin Base Class

All extensions must inherit from the abstract `Plugin` class defined in [`src/Neo/Plugins/Plugin.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Plugins/Plugin.cs). This base class provides the infrastructure for automatic registration and lifecycle management.

When a plugin is instantiated, the constructor automatically adds the instance to the static `Plugin.Plugins` list (line 33) and initializes a logger (lines 107-110). The framework discovers plugins by scanning the `PluginsDirectory` (lines 38-40), which defaults to a `Plugins` folder relative to the executable.

Key virtual methods for customization include:

- **`Configure()`** (lines 14-18): Called during construction to load plugin-specific JSON configuration via `GetConfiguration()`.
- **`OnSystemLoaded(NeoSystem system)`** (lines 60-62): Invoked after `NeoSystem` initializes core services like the blockchain and P2P networking.
- **`OnMessage(object message)`** (lines 52-55): Handles inter-plugin messages sent via `Plugin.SendMessage()`.

### Configuration and Settings Interfaces

For strongly-typed configuration, implement the `IPluginSettings` interface from [`src/Neo/Plugins/IPluginSettings.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Plugins/IPluginSettings.cs). This interface exposes the `ExceptionPolicy` property (lines 16-17), allowing plugins to declare their preferred failure handling strategy.

Plugins access configuration through the protected `GetConfiguration()` method, which returns the `"PluginConfiguration"` section from the plugin's JSON config file.

### Exception Handling Policies

The `UnhandledExceptionPolicy` enum in [`src/Neo/Plugins/UnhandledExceptionPolicy.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Plugins/UnhandledExceptionPolicy.cs) defines three failure modes (lines 15-19):

- **`Ignore`**: Log the exception and continue execution.
- **`StopPlugin`**: Disable the specific plugin but keep the node running.
- **`StopNode`**: Shut down the entire node process.

Set this policy via the `ExceptionPolicy` property override or through `IPluginSettings` to control isolation boundaries.

### System Integration and Lifecycle

The `NeoSystem` class in [`src/Neo/NeoSystem.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/NeoSystem.cs) triggers plugin loading during static initialization. The static constructor calls `Plugin.LoadPlugins()` (lines 12-13), which scans the `Plugins` directory and instantiates all non-abstract `Plugin` subclasses.

After constructing core actors (blockchain, memory pool, local node), `NeoSystem` iterates through `Plugin.Plugins` and invokes `OnSystemLoaded(this)` (lines 53-55), signaling that plugins may now interact with node services.

## Implementing a Custom Plugin

Creating a custom plugin involves inheriting from the base class, implementing lifecycle hooks, and deploying to the correct directory structure.

### Project Structure and Deployment

Compile your plugin as a .NET class library targeting the same framework as the Neo node. Deploy the output DLL to:

```

<neo-node-exe>/Plugins/<YourPluginName>/

```

Place an optional [`config.json`](https://github.com/neo-project/neo/blob/main/config.json) in the same folder. The framework monitors this directory; changes require a node restart to reload assemblies.

### Basic Plugin Implementation

Here is a minimal plugin that logs initialization and responds to inter-plugin messages:

```csharp
using Neo.Plugins;
using Neo.SmartContract.Native;
using Neo;
using System;

public class HelloWorldPlugin : Plugin
{
    protected override void Configure()
    {
        var config = GetConfiguration();
        Logger.Information("HelloWorldPlugin configured with: {Config}", config.Value);
    }

    protected internal override void OnSystemLoaded(NeoSystem system)
    {
        Logger.Information("HelloWorldPlugin attached to NeoSystem at height {Height}", 
            NativeContract.Ledger.CurrentHash(system.StoreView));
    }

    protected override bool OnMessage(object message)
    {
        if (message is string s && s == "ping")
        {
            Logger.Information("Received ping, sending pong.");
            return true; // Stop propagation
        }
        return false; // Allow other plugins to process
    }

    public override void Dispose()
    {
        Logger.Information("HelloWorldPlugin disposing.");
        base.Dispose();
    }
}

```

This example demonstrates the required inheritance pattern, logger usage through the base class `Logger` property, and proper message handling semantics.

### Handling Configuration

For plugins requiring structured configuration, implement `IPluginSettings` and bind to a JSON section:

```csharp
using Microsoft.Extensions.Configuration;
using Neo.Plugins;

public class AnalyticsSettings : IPluginSettings
{
    public static AnalyticsSettings Current { get; private set; } = new();
    
    public UnhandledExceptionPolicy ExceptionPolicy { get; set; } = UnhandledExceptionPolicy.StopPlugin;
    public string Endpoint { get; set; } = "http://localhost:8080";
    public int BatchSize { get; set; } = 100;

    public static void Load(IConfigurationSection section)
    {
        section.Bind(Current);
    }
}

public class AnalyticsPlugin : Plugin
{
    protected internal override UnhandledExceptionPolicy ExceptionPolicy => 
        AnalyticsSettings.Current.ExceptionPolicy;

    protected override void Configure()
    {
        AnalyticsSettings.Load(GetConfiguration());
        Logger.Information("AnalyticsPlugin configured. Endpoint: {Endpoint}, BatchSize: {BatchSize}",
            AnalyticsSettings.Current.Endpoint, AnalyticsSettings.Current.BatchSize);
    }
}

```

This pattern provides type-safe access to configuration values while exposing the exception policy to the framework.

### Inter-Plugin Communication

Plugins communicate via the static `Plugin.SendMessage` method, which iterates through loaded plugins and invokes `OnMessage` until one returns `true`:

```csharp
// Broadcasting a message from any plugin or service
bool wasHandled = Plugin.SendMessage(new { 
    Type = "BlockProcessed", 
    Height = 1000, 
    Hash = "0x..." 
});

```

The implementation in [`src/Neo/Plugins/Plugin.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Plugins/Plugin.cs) (lines 68-104) ensures that the first plugin handling the message stops further propagation, enabling efficient event subscription patterns.

## Key Source Files

Understanding the Neo plugin architecture requires familiarity with these specific files in the neo-project/neo repository:

| File | Purpose | Location |
|------|---------|----------|
| [`Plugin.cs`](https://github.com/neo-project/neo/blob/main/Plugin.cs) | Abstract base class defining the plugin lifecycle, discovery mechanism, and messaging API. | [`src/Neo/Plugins/Plugin.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Plugins/Plugin.cs) |
| [`IPluginSettings.cs`](https://github.com/neo-project/neo/blob/main/IPluginSettings.cs) | Interface for strongly-typed configuration exposing the `ExceptionPolicy` property. | [`src/Neo/Plugins/IPluginSettings.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Plugins/IPluginSettings.cs) |
| [`UnhandledExceptionPolicy.cs`](https://github.com/neo-project/neo/blob/main/UnhandledExceptionPolicy.cs) | Enum defining failure modes: `Ignore`, `StopPlugin`, `StopNode`. | [`src/Neo/Plugins/UnhandledExceptionPolicy.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Plugins/UnhandledExceptionPolicy.cs) |
| [`NeoSystem.cs`](https://github.com/neo-project/neo/blob/main/NeoSystem.cs) | Core node class that triggers plugin loading and lifecycle callbacks. | [`src/Neo/NeoSystem.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/NeoSystem.cs) |
| [`TestPlugin.cs`](https://github.com/neo-project/neo/blob/main/TestPlugin.cs) | Reference implementation demonstrating configuration loading and event handling. | [`tests/Neo.UnitTests/Plugins/TestPlugin.cs`](https://github.com/neo-project/neo/blob/main/tests/Neo.UnitTests/Plugins/TestPlugin.cs) |

## Summary

- The **Neo plugin architecture** centers on the abstract `Plugin` class in [`src/Neo/Plugins/Plugin.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Plugins/Plugin.cs), providing automatic registration, configuration loading, and lifecycle management.
- Plugins are discovered at runtime by scanning the `Plugins` directory for DLLs containing non-abstract implementations of the base class.
- Key extension points include `Configure()` for JSON configuration, `OnSystemLoaded(NeoSystem)` for service integration, and `OnMessage(object)` for inter-plugin communication.
- The `UnhandledExceptionPolicy` enum controls failure isolation, allowing exceptions to either stop the plugin (`StopPlugin`), halt the node (`StopNode`), or be ignored.
- Implementation requires inheriting from `Plugin`, deploying to the `Plugins` folder, and optionally implementing `IPluginSettings` for strongly-typed configuration.

## Frequently Asked Questions

### What is the base class for all Neo plugins?

All custom plugins must inherit from the abstract `Plugin` class defined in [`src/Neo/Plugins/Plugin.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Plugins/Plugin.cs). This base class handles automatic registration via its constructor (lines 107-110), provides access to the logging infrastructure through the `Logger` property, and defines virtual methods for configuration and lifecycle management that subclasses override to implement custom functionality.

### How does the Neo node discover and load plugins?

The `NeoSystem` class triggers plugin discovery during its static constructor by calling `Plugin.LoadPlugins()` (lines 12-13 in [`src/Neo/NeoSystem.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/NeoSystem.cs)). This method scans the `Plugins` directory (defined in [`Plugin.cs`](https://github.com/neo-project/neo/blob/main/Plugin.cs) lines 38-40), loads each DLL assembly, and uses reflection to instantiate every non-abstract class deriving from `Plugin` (lines 89-100 in [`Plugin.cs`](https://github.com/neo-project/neo/blob/main/Plugin.cs)).

### What lifecycle hooks are available for plugin initialization?

The primary lifecycle hooks include `Configure()`, called during construction to load JSON configuration (lines 14-18 in [`Plugin.cs`](https://github.com/neo-project/neo/blob/main/Plugin.cs)); `OnSystemLoaded(NeoSystem system)`, invoked after core services are ready (lines 53-55 in [`NeoSystem.cs`](https://github.com/neo-project/neo/blob/main/NeoSystem.cs)); and `OnMessage(object message)`, which handles inter-plugin communication (lines 52-55 in [`Plugin.cs`](https://github.com/neo-project/neo/blob/main/Plugin.cs)). Additionally, developers can override `Dispose()` for cleanup when the node shuts down.

### How do plugins handle configuration and error policies?

Plugins load configuration by overriding `Configure()` and calling `GetConfiguration()`, which returns the `"PluginConfiguration"` section from the plugin's JSON config file. For strongly-typed settings, implement `IPluginSettings` (defined in [`src/Neo/Plugins/IPluginSettings.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Plugins/IPluginSettings.cs)) to expose the `ExceptionPolicy` property. This policy, defined in [`UnhandledExceptionPolicy.cs`](https://github.com/neo-project/neo/blob/main/UnhandledExceptionPolicy.cs), controls whether unhandled exceptions stop only the plugin (`StopPlugin`), halt the entire node (`StopNode`), or are ignored.