Menu
 

Build a Valheim Mod: BepInEx, Harmony, Jotunn (2026)

Build a Valheim Mod: BepInEx, Harmony, and Jotunn

Valheim modding is more involved than games that mod through plain text or Lua: a Valheim mod is a compiled C# plugin (a .dll) loaded by BepInEx. The payoff is power - you can patch any part of the game and add real content. This guide covers the full path: the toolchain, a working plugin entry point, adding a custom item, patching game behaviour with Harmony, building, and running your mod on a dedicated server. It assumes you can write basic C# and have the .NET tooling installed.

The mental model: you do not edit the game's files. BepInEx loads your DLL alongside the game, Harmony rewrites game methods at runtime, and Jotunn gives you clean APIs to add items, recipes, and prefabs without fighting the engine. Use Jotunn for content and Harmony for behaviour.

What you'll build

  1. The stack - BepInEx, HarmonyX, Jotunn
  2. Set up the project - assemblies, publicizing, the mod stub
  3. Your first plugin - the entry-point class
  4. Add content with Jotunn - a custom item
  5. Change behaviour with Harmony - patching the game
  6. Build, install, test
  7. Distribute and run on a dedicated server
  8. Common pitfalls

1. The stack

LayerWhat it does
BepInExThe plugin framework/loader. Your DLL goes in BepInEx/plugins and BepInEx loads it into the running game. Install the BepInExPack Valheim from Thunderstore - it is configured for Valheim.
HarmonyXThe runtime patching library (bundled with BepInEx). It lets you run your code before (prefix) or after (postfix) any existing game method without editing the original.
Jotunn (JVL)The community modding library most content mods build on. It wraps the messy parts - registering items, recipes, prefabs, localization, config, and client/server sync - behind tidy managers.

2. Set up the project

You need Visual Studio (with .NET desktop development) and the .NET Framework 4.6.2 targeting pack - Valheim's Unity runtime targets that framework. The fastest start is the official JotunnModStub template, which wires up the references and the post-build copy step for you.

  1. Install the BepInExPack Valheim from Thunderstore into your game folder.
  2. Start from the JotunnModStub project (it references BepInEx, HarmonyX, and Jotunn).
  3. Reference Valheim's own assemblies (chiefly assembly_valheim.dll) from Valheim/Valheim_Data/Managed.
  4. Publicize those assemblies. Game classes have many private members; a publicized copy exposes them so your code and Harmony patches can reach them. JotunnModStub runs the publicizer automatically as a prebuild step.
  5. The build copies your compiled DLL into <ValheimDir>\BepInEx\plugins.

3. Your first plugin (the entry point)

Every Valheim mod has one class that BepInEx instantiates. The attributes are what matter:

using BepInEx;
using HarmonyLib;
using Jotunn.Utils;

namespace MyFirstValheimMod
{
    [BepInPlugin(PluginGUID, PluginName, PluginVersion)]
    [BepInDependency(Jotunn.Main.ModGuid)]
    [NetworkCompatibility(CompatibilityLevel.EveryoneMustHaveMod, VersionStrictness.Minor)]
    internal class MyFirstValheimMod : BaseUnityPlugin
    {
        public const string PluginGUID = "com.yourname.myfirstvalheimmod";
        public const string PluginName = "MyFirstValheimMod";
        public const string PluginVersion = "0.1.0";

        private readonly Harmony harmony = new Harmony(PluginGUID);

        private void Awake()
        {
            Logger.LogInfo($"{PluginName} {PluginVersion} loaded");
            harmony.PatchAll();
        }
    }
}
  • [BepInPlugin] declares your unique GUID, name, and version - use reverse-domain form for the GUID so it never collides.
  • [BepInDependency(Jotunn.Main.ModGuid)] tells BepInEx to load Jotunn before your mod.
  • [NetworkCompatibility(...)] is a Jotunn attribute that declares how your mod behaves across the network. EveryoneMustHaveMod means server and all clients need it (correct for content mods); a purely client-side visual tweak would use a looser level. This is what stops "you have mods the server does not" kicks.
  • harmony.PatchAll() in Awake applies every Harmony patch in your assembly (see section 5).

4. Add content with Jotunn

Jotunn's managers fire events when the game is ready for additions. To add items you wait for PrefabManager.OnVanillaPrefabsAvailable, then clone an existing item and register it. This adds an "EvilSword" cloned from the black-metal sword, craftable at the workbench:

using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;

// in Awake():
PrefabManager.OnVanillaPrefabsAvailable += AddClonedItems;

private void AddClonedItems()
{
    ItemConfig evilSwordConfig = new ItemConfig();
    evilSwordConfig.Name = "$item_evilsword";
    evilSwordConfig.Description = "$item_evilsword_desc";
    evilSwordConfig.CraftingStation = CraftingStations.Workbench;
    evilSwordConfig.AddRequirement("Stone", 1, 1);
    evilSwordConfig.AddRequirement("Wood", 1, 2);

    CustomItem evilSword = new CustomItem("EvilSword", "SwordBlackmetal", evilSwordConfig);
    ItemManager.Instance.AddItem(evilSword);

    // run once, then unsubscribe
    PrefabManager.OnVanillaPrefabsAvailable -= AddClonedItems;
}

Notes:

  • new CustomItem("EvilSword", "SwordBlackmetal", config) creates your prefab by cloning the vanilla SwordBlackmetal - inheriting its model, animations, and stats so you only override what you change.
  • The $item_evilsword values are localization tokens, not literal text. Register the readable strings through Jotunn's LocalizationManager so your item shows a real name in-game.
  • AddRequirement("Stone", 1, 1) sets the crafting cost (amount, and amount-per-upgrade). The item appears at the workbench automatically.

This is the pattern for most content - configure, clone or build, register through the relevant manager (ItemManager, PieceManager, PrefabManager). You rarely need Harmony just to add things.

5. Change behaviour with Harmony

When you want to alter what an existing game method does, you patch it. A Harmony patch is a static class targeting a method, with a Prefix (runs before) and/or Postfix (runs after). For example, to run code every time a player spawns:

using HarmonyLib;

[HarmonyPatch(typeof(Player), nameof(Player.OnSpawned))]
public static class Player_OnSpawned_Patch
{
    [HarmonyPostfix]
    private static void Postfix(Player __instance)
    {
        Jotunn.Logger.LogInfo($"{__instance.GetPlayerName()} spawned in");
    }
}

__instance is Harmony's name for the object the method ran on. Your harmony.PatchAll() call in Awake discovers and applies this class automatically.

Verify every method signature against the real game. Class and method names like Player.OnSpawned come from Valheim's own code - confirm the exact names by decompiling assembly_valheim.dll (in Valheim_Data/Managed) with ILSpy or dnSpy. Game updates rename, re-sign, or restructure methods, which is the single biggest reason a Harmony mod breaks after a patch. Patch the narrowest method that does the job.

6. Build, install, test

  1. Build the project. With the JotunnModStub post-build step, the DLL lands in BepInEx/plugins automatically; otherwise copy it there yourself.
  2. Launch Valheim. Watch the BepInEx console / LogOutput.log for your {PluginName} loaded line - that confirms BepInEx found and ran your plugin.
  3. Test in-game: spawn or craft your item, trigger your patched behaviour, and check the log for errors.

7. Distribute and run on a dedicated server

Valheim mods are published on Thunderstore, and players install them with a mod manager such as r2modman. To run a mod on a dedicated server, the same DLL goes in the server's BepInEx/plugins folder. Whether clients also need it is exactly what your [NetworkCompatibility] level declares: a content mod set to EveryoneMustHaveMod must be installed on the server and every client, at matching versions, or players are rejected at join.

For getting BepInEx and mods onto your server and clients in sync, see Install Mods (r2modman sync) and BepInEx on a Valheim server; for the server itself, Dedicated Server Setup.

8. Common pitfalls

SymptomCause / fix
Plugin never loads (no log line)DLL not in BepInEx/plugins, or BepInEx itself not installed/enabled
private game member won't compileYou are referencing the stock assembly - reference the publicized assembly_valheim instead
Harmony patch silently stops working after an updateValheim renamed/re-signed the method - re-check the signature in a decompiler and update the patch
Players kicked: "incompatible mods"[NetworkCompatibility] mismatch or different mod versions between server and client
Item shows $item_evilsword as its nameLocalization token not registered - add the strings via Jotunn's LocalizationManager
"Disabling BepInEx didn't make my server vanilla"Disabling the loader does not unload already-installed plugins - see Verify Vanilla

Related reading

Host Your Modded Valheim Server with Supercraft

Supercraft runs Valheim dedicated servers with BepInEx supported, mod sync between server and clients, daily backups, and the headroom Ashlands and heavy mod lists need. Build your plugin, push it to Thunderstore, and run it on a server that stays online 24/7.

Rent a Valheim Server

Tired of fighting this issue every patch?

Run a managed Valheim server with us. We handle the patches, mod-version pinning, save backups, and DDoS protection. Set up in 3 minutes, 5 datacenter regions, no contract.

See Valheim hosting plans →
Top