Making Your First Mod¶
This tutorial walks you through creating a simple TerrariaModder mod from scratch.
Prerequisites¶
- .NET Framework 4.8 SDK - Download
- Visual Studio 2019+ or VS Code with C# extension
- TerrariaModder installed in your Terraria folder
What We're Building¶
A simple mod that: - Shows a message when you enter a world - Has a configurable greeting message - Has a keybind to show the message on demand
Step 1: Create the Project Structure¶
Create a new folder for your mod:
src/MyFirstMod/
├── MyFirstMod.csproj
├── manifest.json
├── icon.png <- Optional: mod icon (shown in UI headers)
└── Mod.cs
Step 2: Create the Project File¶
Create MyFirstMod.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<AssemblyName>MyFirstMod</AssemblyName>
<RootNamespace>MyFirstMod</RootNamespace>
<OutputType>Library</OutputType>
<LangVersion>latest</LangVersion>
<OutputPath>..\..\build\plugins\</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Core\TerrariaModder.Core.csproj">
<Private>false</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="Terraria">
<HintPath>..\..\Terraria\Terraria.exe</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="0Harmony">
<HintPath>..\..\Terraria\TerrariaModder\core\deps\0Harmony.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553">
<HintPath>C:\Windows\Microsoft.NET\assembly\GAC_32\Microsoft.Xna.Framework.Game\v4.0_4.0.0.0__842cf8be1de50553\Microsoft.Xna.Framework.Game.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
</Project>
Key settings:
- TargetFramework: Must be net48
- Private: Set to false to avoid copying framework DLLs into your output
- Terraria reference: Allows using Terraria types directly (e.g., Main.NewText()). Optional; advanced mods can use reflection instead (see Tested Patterns)
- 0Harmony reference: Required for Harmony patching
Note: HintPaths assume your mod is in src/YourMod/ with Terraria/ alongside src/. Adjust paths if your layout differs.
Step 3: Create the Manifest¶
Create manifest.json:
{
"id": "my-first-mod",
"name": "My First Mod",
"version": "1.0.0",
"author": "Your Name",
"description": "A simple greeting mod",
"entry_dll": "MyFirstMod.dll",
"icon": "icon.png",
"keybinds": [
{
"id": "show-greeting",
"label": "Show Greeting",
"description": "Display the greeting message",
"default": "G"
}
]
}
Manifest Fields¶
| Field | Required | Description |
|---|---|---|
id |
Yes | Unique identifier (lowercase, hyphens only) |
name |
Yes | Display name |
version |
Yes | Semantic version (x.y.z) |
author |
Yes | Your name |
entry_dll |
No | Main DLL filename (defaults to {id}.dll with hyphens removed) |
description |
Yes | What the mod does |
dependencies |
No | Required mod IDs (loaded first) |
optional_dependencies |
No | Optional mod IDs (loaded first if present) |
incompatible_with |
No | Mod IDs that conflict with this mod |
keybinds |
No | Rebindable hotkeys |
framework_version |
No | Minimum required TerrariaModder version |
terraria_version |
No | Minimum Terraria version |
homepage |
No | Mod homepage URL |
icon |
No | Path to a PNG icon file (relative to mod folder, defaults to icon.png). Shown in panel headers and mod list. |
tags |
No | Mod tags for categorization |
Note on entry_dll: Optional. If omitted, defaults to the mod ID with hyphens removed plus .dll (e.g., my-first-mod → myfirstmod.dll). Specify explicitly if your DLL name differs from this pattern.
Step 4: Create the Mod Class¶
Create Mod.cs:
using Terraria;
using TerrariaModder.Core;
using TerrariaModder.Core.Config;
using TerrariaModder.Core.Logging;
namespace MyFirstMod
{
// Config class — properties auto-generate F6 menu UI and save to core/configs/
public class MyFirstModConfig : ModConfig
{
[Client] public bool ShowOnEnter { get; set; } = true;
[Client] public string GreetingMessage { get; set; } = "Hello, Terraria!";
}
// IMod = required. IModLifecycle = optional (world load/unload hooks).
public class Mod : IMod, IModLifecycle
{
// These must match manifest.json
public string Id => "my-first-mod";
public string Name => "My First Mod";
public string Version => "1.0.0";
private ILogger _log;
private ModContext _context;
private MyFirstModConfig _config;
public void Initialize(ModContext context)
{
_log = context.Logger;
_context = context;
_config = context.GetConfig<MyFirstModConfig>();
// Register our keybind
context.RegisterKeybind("show-greeting", "Show Greeting",
"Display the greeting message", "G", ShowGreeting);
_log.Info("My First Mod initialized!");
}
public void OnContentReady(ModContext context)
{
// Called after all mods are initialized and content IDs are assigned.
// Use this for cross-mod lookups or anything that depends on other mods being loaded.
}
public void OnWorldLoad()
{
if (_config.ShowOnEnter)
ShowGreeting();
}
public void OnWorldUnload()
{
_log.Debug("World unloading");
}
public void Unload()
{
_log.Info("My First Mod unloading");
}
// Optional: Implement this to receive config changes without restart
public void OnConfigChanged()
{
_log.Info("Config changed - reloading settings");
// Re-read any cached config values here
}
private void ShowGreeting()
{
// Get the greeting from config, or use default
string greeting = _context.Config?.Get<string>("greeting") ?? "Hello, Terraria!";
// Show it in the game chat
Main.NewText(greeting, 255, 255, 100); // Yellow text
_log.Info($"Showed greeting: {greeting}");
}
}
}
Step 5: Build¶
Command Line¶
Visual Studio¶
- Add project to the solution
- Build (Ctrl+Shift+B)
Step 6: Deploy¶
Copy the files to your Terraria mods folder:
Terraria/TerrariaModder/mods/my-first-mod/
├── manifest.json (copy from src/MyFirstMod/)
└── MyFirstMod.dll (copy from build/plugins/)
Or add to deploy.bat:
if not exist "%TERRARIA_PATH%\TerrariaModder\mods\my-first-mod" mkdir "%TERRARIA_PATH%\TerrariaModder\mods\my-first-mod"
copy /Y "build\plugins\MyFirstMod.dll" "%TERRARIA_PATH%\TerrariaModder\mods\my-first-mod\" >nul
copy /Y "src\MyFirstMod\manifest.json" "%TERRARIA_PATH%\TerrariaModder\mods\my-first-mod\" >nul
Step 7: Test¶
- Run
TerrariaInjector.exe - Load or create a world
- You should see your greeting message
- Press G to show it again
- Press F6 to open mod menu and change the greeting
Step 8: Check Logs¶
If something doesn't work, check:
Look for [my-first-mod] entries to see your mod's log messages.
Notes for Existing Modders¶
If you're updating a mod from an earlier Core version:
- Recompile against new Core — mods must be recompiled against Core 0.4.0+. Old DLLs that only use basic
IModmethods will still load, but mods using changed APIs (like the oldIModConfiginterface) will fail gracefully and need a recompile. - Config migration is automatic — if your mod used the old
config_schema/config.jsonsystem, user settings migrate automatically to the newcore/configs/location. We encourage adopting the newModConfigclass for free F6 UI, multiplayer scoping, and validation. The legacy migration will eventually be removed. - IModLifecycle is optional —
OnContentReady,OnWorldLoad, andOnWorldUnloadmoved fromIModto the optionalIModLifecycleinterface. AddIModLifecycleto your class declaration to use them. - Multiplayer — add
"multiplayer": "client-only"(or"required"/"optional") to your manifest.json. See Publishing for details.
Next Steps¶
Now that you have a working mod:
- Add a UI panel - Use
DraggablePanel+StackLayoutfrom the Widget Library for instant drag, close, z-order - Add Harmony patches - See Harmony Basics for patching game behavior. Apply patches manually with
_harmony.Patch()in theOnGameReady()lifecycle hook - Add more features - See Tested Patterns for common techniques
- Study real mods - Read the Mod Walkthroughs
- Publish - See Publishing Your Mod
Common Issues¶
"IMod not found"¶
Make sure you're referencing TerrariaModder.Core.csproj correctly.
"Id mismatch" warning¶
The Id property in your Mod class must exactly match the id in manifest.json.
Config not working¶
- Make sure your
ModConfigsubclass properties have[Client]or[Server]attributes - Delete the config file in
TerrariaModder/core/configs/to reset to defaults - Check logs for config parsing errors
Keybind not working¶
- Check the keybind is registered (look for log message)
- Try a different key if there's a conflict
- Make sure you're in-game, not on the menu