CovalencePlugin vs RustPlugin: Differences and Which to Use
RustPlugin is the Rust-specific base class and gives you BasePlayer, [ChatCommand] and the Rust hooks directly. CovalencePlugin exposes the universal IPlayer API, which is meant to run across games. On a Rust-only server, RustPlugin is almost always the better choice. You can convert between the two with `player.IPlayer` and `iplayer.Object as BasePlayer`.
4 min readUpdated Oct 26, 2026
Use RustPlugin for plugins that only run on Rust servers, which is nearly every plugin. Use CovalencePlugin only when you deliberately want code written against Oxide's game-neutral IPlayer API. Both are loaded from the same oxide/plugins folder, both support config, lang, permissions and timers, and both work on Carbon.
The core difference
A plugin class inherits from one base class, and that choice decides what the helper members and default player type look like.
| RustPlugin | CovalencePlugin | |
|---|---|---|
| Player type in commands | BasePlayer | IPlayer |
| Command attribute | [ChatCommand], [ConsoleCommand] | [Command] |
| Player lookup | BasePlayer.FindByID, activePlayerList | covalence.Players / players |
| Player ID | player.UserIDString | player.Id |
| Display name | player.displayName | player.Name |
| Replying | SendReply, player.ChatMessage | player.Reply(text) |
| Typical player hooks | OnPlayerConnected, OnPlayerChat | OnUserConnected, OnUserChat |
| Portable to other games | No | Only if you avoid Rust types |
BasePlayer is the real game object: position, inventory, health, flags, the active item. IPlayer is a thin wrapper that exposes only what every supported game can provide, such as ID, name, connection state, permissions and replying to the player.
When each makes sense
Pick RustPlugin when:
- The plugin touches entities, items, damage, building, inventories or CUI. All of that needs Rust types anyway. See rust-player-basics and rust-items-and-inventories.
- You want the widest set of examples to copy from. Most community plugins use it.
- You need chat-only commands with
[ChatCommand].
Pick CovalencePlugin when:
- The logic is only about identities and messages: bans, mutes, permission helpers, name tracking, simple info commands.
- You maintain the same plugin for more than one game and want one codebase.
- You want a command that is reachable from both players and the server console through one handler.
If you start a CovalencePlugin and find yourself casting to BasePlayer in every method, switch to RustPlugin. You gain nothing from the abstraction at that point.
Command handlers
With RustPlugin, a chat command receives BasePlayer:
[ChatCommand("ping")]
private void CmdPing(BasePlayer player, string command, string[] args)
{
SendReply(player, Msg("Pong", player.UserIDString));
}With CovalencePlugin, [Command] receives IPlayer:
[Command("ping")]
private void CmdPing(IPlayer player, string command, string[] args)
{
player.Reply(Msg("Pong", player.Id));
}Two practical points:
- A
[Command]handler can be called by the server console or RCON as well as by a player. Do not assume aBasePlayerexists behind theIPlayer. Checkplayer.IsServeror the result of the cast before using Rust members. - Do the permission check yourself with
player.HasPermission(PermUse)orpermission.UserHasPermission(player.Id, PermUse). Register permissions inInitwith the usual<pluginname>.<action>naming. See oxide-permissions-and-groups.
For the difference between chat and console commands in general, read chat-commands-vs-console-commands.
Converting between IPlayer and BasePlayer
The two types point to the same player, and conversion is cheap.
// IPlayer -> BasePlayer (null if the player is not a Rust player object, e.g. the server)
BasePlayer ToBase(IPlayer iplayer) => iplayer?.Object as BasePlayer;
// BasePlayer -> IPlayer
IPlayer ToUniversal(BasePlayer player) => player?.IPlayer;
// By ID, without holding a player object
IPlayer found = covalence.Players.FindPlayerById("76561198000000000");
BasePlayer basePlayer = found?.Object as BasePlayer;IPlayer needs using Oxide.Core.Libraries.Covalence;. Always null-check the result: an offline player has an IPlayer entry but its Object may not be an active BasePlayer, and a lookup by name or ID can return nothing.
covalence.Players
covalence.Players (also available as players inside a CovalencePlugin) is the player manager. The members you will use most:
FindPlayerById(string id)returns oneIPlayeror null.FindPlayer(string nameOrId)does a looser search.Connectedenumerates players currently online.Allenumerates every player the server knows about, online or not.
Use this when you need to refer to a player who may be offline, for example in a mute list or a ban note. For online-only work inside a Rust plugin, BasePlayer.activePlayerList is more direct and gives you the real object.
Every IPlayer has Id, Name, IsConnected, Reply(...), Message(...) and permission helpers. Keep stored data keyed by Id (a string), not by the object.
OnUser* vs OnPlayer* hooks
Oxide has two families of player hooks:
- OnPlayer* hooks are Rust-specific and pass
BasePlayer: OnPlayerConnected, OnPlayerDisconnected, OnPlayerChat, OnPlayerRespawned, OnPlayerDeath. - OnUser* hooks are the universal ones and pass
IPlayeror a string ID:OnUserConnected,OnUserDisconnected,OnUserChat,OnUserRespawned, and OnUserPermissionGranted, which receives the user ID and permission name as strings.
The base class does not decide which you can use. Oxide dispatches by method name and checks that each argument is an instance of the declared parameter type. A RustPlugin can declare OnUserConnected(IPlayer player) and a CovalencePlugin can declare OnPlayerConnected(BasePlayer player). Choose by what you need:
- Need inventory, position, health or flags: use the OnPlayer* hook.
- Need only ID, name and a message channel: the OnUser* hook is enough.
- Need to block or edit chat: check the hook page for what a return value does. Do not assume
trueforces anything, because many hooks treat any non-null value as "cancel". See oxide-hooks-explained.
Entity and gameplay hooks such as OnEntityTakeDamage or CanBuild have no universal version. They are Rust hooks regardless of base class.
Carbon compatibility
Carbon loads Oxide plugins, including both RustPlugin and CovalencePlugin classes, and it accepts the oxide.* console commands. Files go in carbon/plugins instead of oxide/plugins, with configs in carbon/configs. You do not need to pick a base class for Carbon's sake. If you write a plugin for Oxide using either one, Carbon runs the same file. Differences between the two frameworks are covered in oxide-vs-carbon.
Common mistakes
- Treating
IPlayer.Objectas always valid. It can be null or not aBasePlayer. - Using
player.UserIDStringin a CovalencePlugin command. The member there isplayer.Id. - Mixing
[ChatCommand]signatures (BasePlayer) with[Command](IPlayer). Oxide cannot bind the wrong parameter type, and the command will fail or be skipped. - Expecting a universal plugin to stay portable after adding Rust hooks and entity code.
Recommendation
Default to RustPlugin. Keep IPlayer in your toolbox for lookups through covalence.Players and for identity-only code, and convert with player.IPlayer or iplayer.Object as BasePlayer when you need to cross over. To see a full starting structure with config, lang and permissions, follow how-to-make-a-rust-plugin, or use the plugin generator to produce a working RustPlugin from a description.
FAQ
Can a RustPlugin use IPlayer and covalence.Players?
Yes. Both base classes derive from Oxide's plugin system, and the covalence library is available to Rust plugins too. You can look up an IPlayer with covalence.Players.FindPlayerById(id) inside a RustPlugin. This is useful for cross-game helpers or for reading a player's name and ID without touching Rust types.
Can a CovalencePlugin use Rust hooks like OnEntityTakeDamage?
Yes. Hook dispatch is by method name and parameter types, regardless of the base class. Declaring private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) works in either. But once you use Rust types and hooks, the plugin is no longer portable, so the main benefit of CovalencePlugin is lost.
Does the plugin file name still have to match the class name?
Yes. The rule is the same for both base classes: the file name must match the main class, such as MyPlugin.cs containing class MyPlugin. A mismatch produces an error. See plugin-filename-must-match-main-class.
Which base class is faster at runtime?
Neither is meaningfully faster. Performance depends on what your hooks do, not on the base class. Heavy work in frequent hooks such as damage or input is what triggers slow-hook warnings. See rust-plugin-performance.
Do I need to rewrite a plugin to move from CovalencePlugin to RustPlugin?
Mostly small edits. Change the base class, then replace IPlayer command signatures with BasePlayer, switch [Command] to [ChatCommand] where you want chat-only commands, and rename OnUser* hooks to their OnPlayer* equivalents. Permission, config and lang code stays identical.
More guides
Skip the C#: describe your plugin
Open generator