Skip to main content
Dalamud is a sophisticated plugin framework for FFXIV that uses a multi-layered architecture to safely inject managed code into the game process. This page explains how Dalamud is structured and how it boots.

Architecture Overview

Dalamud’s architecture consists of multiple components working together to provide a stable plugin development environment:

Components

Dalamud is composed of several distinct components, each serving a specific purpose:
The first component in the boot chain. Written in C++, this component:
  • Loads the .NET Core runtime via hostfxr
  • Initializes the CoreCLR hosting environment
  • Kicks off Dalamud.Injector in managed code
  • Handles low-level process initialization
A managed C# component that performs DLL injection:
  • Injects Dalamud.Boot into the target FFXIV process
  • Manages the injection timing and methodology
  • Handles error cases during injection
  • Coordinates with XIVLauncher for process management
A native DLL loaded into the game process that:
  • Loads the .NET Core runtime into the active process
  • Bootstraps the managed Dalamud core
  • Rewrites the target process entrypoint when necessary
  • Sets up exception handling and crash reporting
  • Initializes MinHook for function hooking
The main managed framework providing:
  • Core API and game bindings
  • Plugin loading and management infrastructure
  • Service container and dependency injection
  • Event system and game state tracking
  • UI framework integration (ImGui)
A special testbed plugin that:
  • Has access to Dalamud internals
  • Used to prototype new framework features
  • Tests plugin API changes before public release
  • Validates core functionality

Boot Pipeline

The Dalamud boot process follows a carefully orchestrated pipeline to ensure safe initialization:
1

XIVLauncher Starts

XIVLauncher manages the game launch and determines when to inject Dalamud based on user configuration.
2

Dalamud.Injector.Boot Initializes

The boot component loads the .NET Core runtime and starts the managed injector:
// Loads CoreCLR via hostfxr
hostfxr_initialize_for_runtime_config()
hostfxr_get_runtime_delegate()
3

Dalamud.Injector Performs Injection

The injector injects Dalamud.Boot.dll into the FFXIV process using platform-appropriate injection techniques.
4

Dalamud.Boot Loads Runtime

Inside the game process, Dalamud.Boot loads .NET Core and calls into EntryPoint.Initialize():
// From Dalamud.Boot/dllmain.cpp
InitializeImpl(lpParam, hMainThreadContinue)
5

EntryPoint Initializes

The managed entry point sets up logging, configuration, and creates the main Dalamud instance:
// From Dalamud/EntryPoint.cs:57
public static void Initialize(IntPtr infoPtr, IntPtr mainThreadContinueEvent)
{
    var infoStr = Marshal.PtrToStringUTF8(infoPtr)!;
    var info = JsonConvert.DeserializeObject<DalamudStartInfo>(infoStr)!;
    new Thread(() => RunThread(info, mainThreadContinueEvent)).Start();
}
6

Dalamud Core Constructs

The main Dalamud class initializes core subsystems:
// From Dalamud/Dalamud.cs:52
public Dalamud(DalamudStartInfo info, ReliableFileStorage fs, 
               DalamudConfiguration configuration, IntPtr mainThreadContinueEvent)
{
    // Initialize SigScanner for game memory scanning
    scanner = new TargetSigScanner(...);
    
    // Initialize service container and services
    ServiceManager.InitializeProvidedServices(
        this, fs, configuration, scanner, localization);
    
    // Start early-loading services
    ServiceManager.InitializeEarlyLoadableServices();
}
7

Services Initialize

The Service Manager initializes all framework services in dependency order. See Dependency Injection for details.
8

Game Thread Resumes

Once blocking services are ready, Dalamud signals the game’s main thread to continue:
// From Dalamud/Dalamud.cs:91
void KickoffGameThread()
{
    Log.Verbose("=============== GAME THREAD KICKOFF ===============");
    Timings.Event("Game thread kickoff");
    Windows.Win32.PInvoke.SetEvent(new HANDLE(mainThreadContinueEvent));
}
9

Plugins Load

The Plugin Manager loads plugins based on their LoadRequiredState and LoadSync settings. See Plugin Lifecycle for details.

Thread Model

Dalamud operates across multiple threads to ensure safe interaction with the game:

Main Game Thread

The game’s primary rendering and logic thread. Plugins should avoid blocking this thread to prevent frame drops.

Framework Thread

Dalamud’s framework update thread, synchronized with the game’s update tick. Most plugin logic runs here.

Service Initialization Threads

Background threads used during startup to initialize services without blocking the game.

Plugin Loader Threads

Separate threads for loading plugins asynchronously, preventing startup delays.
Always use Framework.RunOnFrameworkThread() or Framework.RunOnTick() when you need to execute code that interacts with game state from another thread.

Memory Architecture

Dalamud uses several techniques to safely interact with game memory:

Signature Scanning

Dalamud locates game functions and data structures using byte pattern signatures:
// From Dalamud/Dalamud.cs:68
scanner = new TargetSigScanner(
    true, 
    new FileInfo(Path.Combine(cacheDir.FullName, $"{this.StartInfo.GameVersion}.json"))
);
Signatures are cached per game version to improve startup performance.

Function Hooking

Dalamud uses Reloaded.Hooks for type-safe function hooking:
// Example hook pattern
this.myHook = Hook<MyDelegate>.FromAddress(address, MyDetour);
this.myHook.Enable();

ClientStructs Integration

Dalamud integrates FFXIVClientStructs for type-safe access to game structures:
// From Dalamud/Dalamud.cs:232
InteropGenerator.Runtime.Resolver.GetInstance.Setup(
    Service<TargetSigScanner>.Get().SearchBase, 
    $"{this.StartInfo.GameVersion}", 
    new FileInfo(Path.Combine(cacheDir.FullName, "cs.json"))
);
FFXIVClientStructs.Interop.Generated.Addresses.Register();
InteropGenerator.Runtime.Resolver.GetInstance.Resolve();

Isolation and Safety

Dalamud provides several layers of isolation to ensure stability:
1

Assembly Load Contexts

Each plugin loads in its own AssemblyLoadContext, preventing assembly conflicts:
// From Dalamud/Plugin/Internal/Loader/PluginLoader.cs:34
this.context = (ManagedLoadContext)this.contextBuilder.Build();
2

Exception Handling

Dalamud catches and logs exceptions from plugins to prevent crashes:
// From Dalamud/EntryPoint.cs:160
AppDomain.CurrentDomain.UnhandledException += OnUnhandledExceptionDefault;
3

Service Scoping

Plugins receive scoped service instances that can be safely disposed:
// Services are injected through IoC container
// See ServiceContainer.CreateAsync() in ServiceContainer.cs:94
While Dalamud provides isolation, plugins can still cause instability through unsafe memory operations or excessive resource usage. Always test thoroughly!

Version Management

Dalamud uses API levels to handle breaking changes:
// From Dalamud/Plugin/Internal/PluginManager.cs:81
static PluginManager()
{
    DalamudApiLevel = typeof(PluginManager).Assembly.GetName().Version!.Major;
}
As of Dalamud 9.x and later, the API level always matches the major version number. Only plugins built for the current API level will load.

Next Steps

Plugin Lifecycle

Learn how plugins are loaded, initialized, and unloaded

Dependency Injection

Understand Dalamud’s IoC container and service system

Service Locator

Learn how to access Dalamud services in your plugin

Building Dalamud

Compile Dalamud from source

Build docs developers (and LLMs) love