---
title: Plugins
---
# Plugins
## Protocol
Plugins are executable applications that communicate with Nu by exchanging serialized data over a stream (much in the same way VSCode plugins do). The stream may either be stdio, which all plugins support, or a local socket (e.g. Unix domain socket or Windows named pipe) when supported. The protocol is split into two stages.
The first stage of the protocol deals with the initial discovery of the plugin. When a plugin is registered the plugin is executed and asked to reply with its configuration. Just as with commands, plugins have a signature that they respond to Nu with. Once Nu has this signature, it knows how to later invoke the plugin to do work.
The second stage is the actual doing of work. Here the plugins are executed and sent serialized input data. The plugin then replies with the serialized output data.
For more detailed information about how exactly this communication works, especially if trying to implement a plugin in a language other than Rust, see the [plugin protocol](plugin_protocol_reference.md) section.
## Discovery
Nu keeps a registry of plugins known as the ‘plugin registry file’ at the file system location defined by configuration variable `$nu.plugin-path`. To add a plugin, execute `plugin add <path_to_plugin_executable>` in a Nu shell. The plugin's signatures will be added to the plugin registry file for future launches of Nu. To make them available immediately, call `plugin use <plugin_name>`.
## Launch environment
When launched in `stdio` mode, `stdin` and `stdout` are redirected for use in the plugin protocol, and must not be used for other purposes. Stderr is inherited, and may be used to print to the terminal.
When launched in `local-socket` mode, `stdin` and `stdout` can also be used to interact with the user's terminal. This is the default for Rust plugins unless `local-socket` is disabled, and can be checked for by calling [`EngineInterface::is_using_stdio()`](https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html#method.is_using_stdio). Plugins may fall back to `stdio` mode if sockets are not working for some reason, so it is important to check this if you are going to be using `stdin` or `stdout`.
Environment variables set in the shell are set in the environment of a plugin when it is launched from a plugin call.
Plugins are always started with the directory of their executable as their working directory. This is because they may be sent calls with different shell working directory contexts over time. [`EngineInterface::get_current_dir()`](https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html#method.get_current_dir) can be used to determine the current working directory of the context of a call. For more information, see [this section](#current-directory).
## Creating a plugin (in Rust)
In this section, we'll walk through creating a Nu plugin using Rust.
Let's create our project. For this example, we'll create a simple `len` command which will return the length of strings it's passed.
First off, we'll create our plugin:
```sh
cargo new nu_plugin_len
cd nu_plugin_len
```
Next, we'll add `nu` to our project's dependencies.
```sh
cargo add nu-plugin nu-protocol
```
The `Cargo.toml` file should now look something like the following.
```toml
[package]
name = "nu_plugin_len"
version = "0.1.0"
edition = "2024"
[dependencies]
nu-plugin = "0.104.0"
nu-protocol = "0.104.0"
```
With this, we can open up `src/main.rs` and create our plugin.
```rust
use nu_plugin::{EvaluatedCall, JsonSerializer, serve_plugin};
use nu_plugin::{EngineInterface, Plugin, PluginCommand, SimplePluginCommand};
use nu_protocol::{LabeledError, Signature, Type, Value};
struct LenPlugin;
impl Plugin for LenPlugin {
fn version(&self) -> String {
env!("CARGO_PKG_VERSION").into()
}
fn commands(&self) -> Vec<Box<dyn PluginCommand<Plugin = Self>>> {
vec![
Box::new(Len),
]
}
}
struct Len;