Plugins & modules
A plugin is a self-contained, portable feature bundle: a .uplugin descriptor file plus
one or more C++ modules and optional content/resources. Use plugins when the feature is
reusable across projects, optional (so it can be disabled), or ships as an editor tool.
Compare with project modules (ue-module-and-build-system): project modules compile into your
game and can't travel without it; plugins drop into any project's Plugins/ folder.
When to use this skill
- Creating a reusable runtime system, editor tool, or third-party SDK wrapper.
- Deciding whether to put new code in a project module or a plugin.
- Structuring a plugin that contains both runtime and editor modules.
- Enabling, disabling, or adding a dependency on another plugin.
- A plugin or its modules fail to load at startup.
- Plugin content doesn't mount or assets aren't found under
/PluginName/.
Plugin vs project module
| Project module | Plugin | |
|---|---|---|
| Lives in | Source/<Name>/ inside the project |
Plugins/<Name>/ in the project or engine |
| Portability | Not portable (game-specific) | Drop into any project and enable |
| Optional? | Always compiled | Can be disabled per-project |
| Can bundle content? | No (content lives in project Content/) |
Yes (CanContainContent: true) |
| Multiple modules? | One .Build.cs per module |
Many modules, each with its own .Build.cs |
Choose a plugin when: the feature will be used in more than one project, it is optional, or it is an editor-only tool you want to ship separately.
Plugin folder structure
Plugins/MyFeature/
├── MyFeature.uplugin # required: plugin descriptor
├── Source/
│ ├── MyFeature/ # runtime module (Build.cs, Public/, Private/)
│ └── MyFeatureEditor/ # optional editor-only module
├── Content/ # optional: assets mounted at /MyFeature/
├── Config/
│ └── DefaultMyFeature.ini # optional: plugin ini (game plugin convention)
└── Resources/
└── Icon128.png # 128x128 png shown in Plugin Browser
Each subdirectory under Source/ is its own module with its own *.Build.cs
(ue-module-and-build-system). Plugin content mounts under /MyFeature/...
(ue-project-structure). The engine and UnrealBuildTool discover plugins by scanning for
.uplugin files; organise plugins in subdirectories under Plugins/ as needed, but the
engine won't scan into a discovered plugin's own subdirectories.
The .uplugin descriptor
The descriptor is JSON and maps to FPluginDescriptor
(Runtime/Projects/Public/PluginDescriptor.h:38). A minimal code plugin:
{
"FileVersion": 3,
"FriendlyName": "My Feature",
"Version": 1,
"VersionName": "1.0",
"EnabledByDefault": true,
"CanContainContent": false,
"Modules": [
{ "Name": "MyFeature", "Type": "Runtime", "LoadingPhase": "Default" },
{ "Name": "MyFeatureEditor", "Type": "Editor", "LoadingPhase": "Default" }
],
"Plugins": [
{ "Name": "EnhancedInput", "Enabled": true }
]
}
Key fields (FPluginDescriptor fields, PluginDescriptor.h):
| JSON key | Field | Notes |
|---|---|---|
FileVersion |
— | Always 3 for current UE. Required. |
Version |
Version |
Integer; must increase with each release. |
VersionName |
VersionName |
Human-readable version string shown in UI. |
EnabledByDefault |
EnabledByDefault (EPluginEnabledByDefault:28) |
true/false/omit (unspecified). |
CanContainContent |
bCanContainContent:127 |
Must be true for the Content/ folder to mount. |
Modules |
Modules:90 — TArray<FModuleDescriptor> |
Code modules; see below. |
Plugins |
Plugins:174 — TArray<FPluginReferenceDescriptor> |
Other plugins this one depends on. |
For full field reference see references/uplugin-descriptor.md.
Module types and loading phases
Each entry in Modules maps to FModuleDescriptor
(Runtime/Projects/Public/ModuleDescriptor.h:154). The two most important fields:
Type (EHostType, ModuleDescriptor.h:82) — controls which targets load the module:
| Type | Loads in |
|---|---|
Runtime |
All targets (game, editor, server, client) |
RuntimeNoCommandlet |
Runtime, but not editor commandlets |
Editor |
Editor only — stripped from packaged games |
EditorNoCommandlet |
Editor, not commandlets |
Developer / DeveloperTool |
Builds with developer tools enabled |
UncookedOnly |
Uncooked builds only (Blueprint nodes, etc.) |
ServerOnly / ClientOnly |
Dedicated server or client targets |
Program |
Standalone programs only |
LoadingPhase (ELoadingPhase, ModuleDescriptor.h:24) — controls when the module is
loaded relative to engine startup. Common choices:
| Phase | When | Use for |
|---|---|---|
PostConfigInit |
After config, before CoreUObject | Low-level hooks |
PreDefault |
Just before Default | Types/factories other modules depend on |
Default |
Standard — after game modules are loaded | Nearly all gameplay/plugin code |
PostEngineInit |
After engine is fully initialized | Systems that need everything available |
None |
Not loaded automatically | Load on demand via FModuleManager |
All phases are in ELoadingPhase::Type (ModuleDescriptor.h:26–59). Cross-reference
ue-module-and-build-system for the build-side implications of each phase.
Module C++ wiring
Every plugin module needs exactly one registration macro in one .cpp:
// MyFeatureModule.cpp
#include "Modules/ModuleManager.h"
#include "MyFeatureModule.h"
IMPLEMENT_MODULE(FMyFeatureModule, MyFeature)
void FMyFeatureModule::StartupModule()
{
// Load any modules this one depends on to guarantee ordering
FModuleManager::Get().LoadModuleChecked(TEXT("MyDependency"));
// Register services, type actions, detail customizations…
}
void FMyFeatureModule::ShutdownModule()
{
// Mirror every registration from StartupModule
}
IMPLEMENT_MODULEis inRuntime/Core/Public/Modules/ModuleManager.h:946. It registers the module with theFModuleManagerand installs UE's memory allocator overrides (PER_MODULE_BOILERPLATE). Every plugin module must have exactly one call.IModuleInterface::StartupModule():49 /ShutdownModule():79 inRuntime/Core/Public/Modules/ModuleInterface.h.- Use
FDefaultModuleImpl(no startup logic) orFDefaultGameModuleImpl(gameplay module) when you don't need custom init. Seeue-module-and-build-systemfor these helpers.
Editor module pattern — guard editor-only includes with #if WITH_EDITOR in headers shared
with runtime modules:
// MyFeatureEditor/Private/MyFeatureEditorModule.cpp
#include "Modules/ModuleManager.h"
class FMyFeatureEditorModule : public IModuleInterface
{
public:
virtual void StartupModule() override { /* register detail panels, asset actions */ }
virtual void ShutdownModule() override { /* unregister */ }
};
IMPLEMENT_MODULE(FMyFeatureEditorModule, MyFeatureEditor)
Enabling plugins
In a project: add to the .uproject Plugins array or use Edit → Plugins in the editor.
Each entry is a FPluginReferenceDescriptor (PluginReferenceDescriptor.h:26):
"Plugins": [
{ "Name": "MyFeature", "Enabled": true }
]
Engine vs project plugins:
- Engine plugins live under the engine's
Engine/Plugins/. Available to all projects. - Project plugins live under the project's
Plugins/. Local to that project.
The plugin manager discovers all .uplugin files in both locations at startup.
Content-only plugins
A plugin with no source modules but with CanContainContent: true and a Content/ folder
mounts as a content package. The descriptor omits the Modules array entirely:
{
"FileVersion": 3,
"FriendlyName": "Shared Assets",
"Version": 1,
"VersionName": "1.0",
"EnabledByDefault": true,
"CanContainContent": true
}
Assets are referenced as /SharedAssets/... in the asset browser. No C++ required.
Querying plugins at runtime
IPluginManager (Runtime/Projects/Public/Interfaces/IPluginManager.h:284) is the singleton
for querying and mounting plugins. IPlugin (IPluginManager.h:110) represents one plugin.
#include "Interfaces/IPluginManager.h"
// Check if a plugin is enabled (safe to query during gameplay)
TSharedPtr<IPlugin> Plugin = IPluginManager::Get().FindPlugin(TEXT("MyFeature"));
if (Plugin.IsValid() && Plugin->IsEnabled())
{
FString ContentPath = Plugin->GetMountedAssetPath(); // e.g. "/MyFeature/"
FString BaseDir = Plugin->GetBaseDir(); // filesystem path
}
// Enumerate all enabled plugins with content
for (TSharedRef<IPlugin> P : IPluginManager::Get().GetEnabledPluginsWithContent())
{
// P->GetName(), P->GetMountedAssetPath(), P->GetDescriptor()
}
Key IPluginManager methods (all pure virtual, IPluginManager.h):
| Method | Line | Notes |
|---|---|---|
Get() |
667 | Singleton accessor |
FindPlugin(Name) |
393 | Find by name; returns null if not discovered |
FindEnabledPlugin(Name) |
404 | Returns null if not enabled |
GetEnabledPlugins() |
428 | All enabled plugins |
GetEnabledPluginsWithContent() |
435 | Enabled plugins that can contain content |
GetDiscoveredPlugins() |
454 | All discovered plugins (enabled or not) |
Key IPlugin methods:
| Method | Notes |
|---|---|
GetName() |
Internal name (matches folder/.uplugin) |
IsEnabled() |
Whether the plugin is currently enabled |
IsMounted() |
Whether content is mounted (content plugins) |
GetMountedAssetPath() |
Virtual root, e.g. /MyFeature/ |
GetBaseDir() |
Filesystem path to plugin directory |
GetDescriptor() |
Full FPluginDescriptor struct |
GetType() |
EPluginType — Engine / Project / External / Mod |
For explicit-load plugins and runtime mounting see references/plugin-dependencies-and-packaging.md.
Plugin dependency hierarchy
Plugins can declare dependencies on other plugins via the Plugins array in .uplugin. The
dependency must be enabled before the plugin that depends on it. The engine enforces a
one-way hierarchy: engine modules/plugins are higher-level than project modules/plugins. An
engine plugin cannot depend on a project plugin; a project plugin can depend on an engine
plugin. Circular dependencies don't link.
For code-level dependencies between modules inside or across plugins, list the module in
PublicDependencyModuleNames / PrivateDependencyModuleNames in Build.cs
(ue-module-and-build-system).
Gotchas
- Editor module type mismatch — a module containing
#if WITH_EDITOReditor-only code must beType: "Editor"(orEditorNoCommandlet), notRuntime. Packaging will fail or strip the code if the type is wrong. - Missing plugin dependency in
.uplugin— the dependency plugin may not be enabled or may load after the dependent, causing startup failures even if code links fine. - Content not mounting —
CanContainContentmust betrueand assets placed underContent/. CheckIPlugin::IsMounted()at runtime to confirm. - Circular plugin/module deps — won't link. Factor shared types into a lower-level module.
- Engine vs project plugin confusion — engine plugins are available globally; project
plugins are local. Copying a plugin between the two locations changes its
EPluginType. - Wrong LoadingPhase — if another module at
Defaultphase needs your plugin's types but your plugin loads atDefaulttoo, ordering is undefined. UsePreDefaultfor providers. - bExplicitlyLoaded — plugins with this flag set in the descriptor do not load
automatically. They must be mounted via
IPluginManager::MountExplicitlyLoadedPlugin(IPluginManager.h:556). - Config files not packaged — plugin config files are not automatically packaged; copy
them to the project's
Config/folder before distribution.
References & source material
Engine source (UE 5.8, under E:\Program Files\Epic Games\UE_5.8\Engine\Source\):
Runtime/Projects/Public/PluginDescriptor.h—FPluginDescriptor:38,EPluginEnabledByDefault:28,Modulesfield:90,bCanContainContent:127,Pluginsfield:174.Runtime/Projects/Public/ModuleDescriptor.h—FModuleDescriptor:154,EHostTypenamespace:82,ELoadingPhasenamespace:24.Runtime/Projects/Public/PluginReferenceDescriptor.h—FPluginReferenceDescriptor:26,bEnabled:32,bOptional:35.Runtime/Projects/Public/Interfaces/IPluginManager.h—IPlugin:110,IPluginManager:284,FindPlugin:393,FindEnabledPlugin:404,GetEnabledPlugins:428,GetEnabledPluginsWithContent:435,GetDiscoveredPlugins:454,Get():667.Runtime/Core/Public/Modules/ModuleManager.h—IMPLEMENT_MODULE:946.Runtime/Core/Public/Modules/ModuleInterface.h—IModuleInterface,StartupModule:49,ShutdownModule:79.
Real example descriptor: E:\Program Files\Epic Games\UE_5.8\Engine\Plugins\FX\Niagara\Niagara.uplugin
Official docs (UE 5.8):
- Plugins in Unreal Engine — https://dev.epicgames.com/documentation/unreal-engine/plugins-in-unreal-engine
- Setting Up Your Production Pipeline — https://dev.epicgames.com/documentation/unreal-engine/setting-up-your-production-pipeline-in-unreal-engine
Related skills: ue-module-and-build-system (build mechanics, Build.cs, IMPLEMENT_MODULE
variants), ue-project-structure (.uproject layout, enabling plugins), ue-editor-scripting-and-python
(editor automation within plugins).
Deep-dive references in this skill:
- references/uplugin-descriptor.md — full
.upluginfield reference,FPluginDescriptorfield-by-field, module descriptor detail. - references/plugin-structure-and-modules.md — plugin folder conventions, multi-module patterns, editor vs runtime split, content config.
- references/plugin-dependencies-and-packaging.md —
plugin dependency rules,
FPluginReferenceDescriptor, explicit-load plugins, packaging for distribution,bOptionaldependencies.