Guide
The MonoGame Content Pipeline
The content pipeline converts raw assets (images, audio, fonts, models, data files) into optimised binary formats at build time so they load fast at runtime. Understanding it is essential for any MonoGame project.
Download the runnable sample project
Use the verified ZIP bundle for this article to review the extracted example files, run the sample host, and repackage the sources without bin or obj folders.
MGCB Editor setup
The MGCB Editor is a graphical tool for managing your Content.mgcb file. Install it as a .NET tool:
dotnet tool install -g dotnet-mgcb-editor
mgcb-editor Content/Content.mgcb
You can also edit Content.mgcb as a text file. Each entry specifies the importer, processor, and build action for an asset.
#begin player.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:TextureFormat=Color
/build:player.png
Loading textures
Place .png or .jpg files in the Content folder and add them via the MGCB Editor. At runtime, load them with Content.Load<Texture2D>.
// The name matches the file without extension
Texture2D playerTexture = Content.Load<Texture2D>("player");
// For textures in subfolders:
Texture2D tilesetTexture = Content.Load<Texture2D>("Tilesets/grass");
Texture processor options
- PremultiplyAlpha — Required for correct alpha blending with SpriteBatch (default: true).
- GenerateMipmaps — Enable for 3D textures that appear at varying distances.
- TextureFormat — Use
DxtCompressedfor smaller file sizes orColorfor pixel-perfect art. - ColorKeyEnabled — Replaces a background colour with transparency (useful for legacy sprites).
SpriteFont files
Create a .spritefont XML file to define the font family, size, and character ranges. The pipeline rasterises the font into a texture atlas.
<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<FontName>Arial</FontName>
<Size>14</Size>
<Spacing>0</Spacing>
<UseKerning>true</UseKerning>
<Style>Regular</Style>
<CharacterRegions>
<CharacterRegion>
<Start> </Start>
<End>~</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>
SpriteFont font = Content.Load<SpriteFont>("DefaultFont");
_spriteBatch.DrawString(font, "Hello!", new Vector2(10, 10), Color.White);
// Measure text size for centring
Vector2 size = font.MeasureString("Hello!");
Vector2 centred = new Vector2(
(screenWidth - size.X) / 2f,
(screenHeight - size.Y) / 2f);
Audio assets
Add .wav files for sound effects and .ogg or .mp3 for music. The pipeline converts them to the platform-optimal format.
// Sound effects (short, in-memory)
SoundEffect jump = Content.Load<SoundEffect>("Sounds/jump");
jump.Play(volume: 0.8f, pitch: 0f, pan: 0f);
// Create an instance for more control
SoundEffectInstance jumpInstance = jump.CreateInstance();
jumpInstance.Volume = 0.8f;
jumpInstance.IsLooped = false;
jumpInstance.Play();
// Music (streamed)
Song bgm = Content.Load<Song>("Music/theme");
MediaPlayer.IsRepeating = true;
MediaPlayer.Volume = 0.5f;
MediaPlayer.Play(bgm);
Audio quality tips
- Use 44.1 kHz 16-bit WAV for sound effects for the best compatibility.
- Compress music to OGG Vorbis to save disk space; the pipeline handles decoding.
- Keep sound effects under 2 seconds for instant playback; longer sounds should be streamed as Songs.
3D models
Export from Blender, Maya, or 3ds Max as .fbx (recommended) or .obj. The MGCB Editor uses the FbxImporter or OpenAssetImporter to process them.
Model ship = Content.Load<Model>("Models/ship");
// Draw with BasicEffect
foreach (ModelMesh mesh in ship.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = Matrix.Identity;
effect.View = _camera.View;
effect.Projection = _camera.Projection;
effect.EnableDefaultLighting();
}
mesh.Draw();
}
Model processor options
- Scale — Scale the model at import time (e.g., Blender uses metres, you may want centimetres).
- GenerateTangentFrames — Required for normal mapping.
- DefaultEffect — Choose
BasicEffector a custom effect to apply to all meshes. - PremultiplyTextureAlpha — Match your SpriteBatch blending expectations.
Effect files (shaders)
Write HLSL shaders in .fx files and add them to the content project. The pipeline compiles them for the target platform.
Effect myShader = Content.Load<Effect>("Effects/MyShader");
// Set parameters
myShader.Parameters["Intensity"].SetValue(0.8f);
myShader.Parameters["MainTexture"].SetValue(_texture);
// Apply in a SpriteBatch draw
_spriteBatch.Begin(effect: myShader);
_spriteBatch.Draw(_texture, Vector2.Zero, Color.White);
_spriteBatch.End();
DesktopGL uses OpenGL shaders. If you target both DirectX and OpenGL, you may need separate .fx files or use the OPENGL/DIRECTX preprocessor directives.
Custom data files
For JSON, XML, or CSV data files (level data, dialogue, item databases), you can either process them through a custom importer or load them directly at runtime without the pipeline.
// Option 1: Skip the pipeline, load raw file
// Set Build Action to "Copy" in the MGCB Editor
string json = File.ReadAllText(
Path.Combine(Content.RootDirectory, "Data", "levels.json"));
var levels = JsonSerializer.Deserialize<List<LevelData>>(json);
// Option 2: Use a custom importer (see below) to process at build time
var levels = Content.Load<List<LevelData>>("Data/levels");
Writing a custom importer
A custom importer reads a raw file format and converts it into an intermediate object. Create a separate class library project, reference MonoGame.Framework.Content.Pipeline, and implement ContentImporter<T>.
using Microsoft.Xna.Framework.Content.Pipeline;
[ContentImporter(".csv", DisplayName = "CSV Importer",
DefaultProcessor = "CsvProcessor")]
public class CsvImporter : ContentImporter<string[][]>
{
public override string[][] Import(string filename,
ContentImporterContext context)
{
var lines = File.ReadAllLines(filename);
return lines.Select(line => line.Split(',')).ToArray();
}
}
Writing a custom processor
A processor transforms the imported intermediate data into the final type your game will use. It runs at build time, so heavy parsing happens once rather than every game launch.
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
[ContentProcessor(DisplayName = "CSV Processor")]
public class CsvProcessor : ContentProcessor<string[][], ItemData[]>
{
public override ItemData[] Process(string[][] input,
ContentProcessorContext context)
{
return input.Skip(1) // skip header row
.Select(row => new ItemData
{
Id = int.Parse(row[0]),
Name = row[1],
Value = int.Parse(row[2])
})
.ToArray();
}
}
[ContentTypeWriter]
public class ItemDataWriter : ContentTypeWriter<ItemData[]>
{
protected override void Write(ContentWriter output, ItemData[] value)
{
output.Write(value.Length);
foreach (var item in value)
{
output.Write(item.Id);
output.Write(item.Name);
output.Write(item.Value);
}
}
public override string GetRuntimeReader(TargetPlatform targetPlatform)
=> typeof(ItemDataReader).AssemblyQualifiedName;
}
Troubleshooting
Common errors and fixes
- ContentLoadException: Could not find file — Ensure the asset name in
Content.Loadmatches the file name without extension and the correct subfolder path. - Build error: Importer not found — Check the MGCB Editor references your pipeline extension DLL.
- Shader compilation failure — Verify your HLSL syntax and that you target the correct shader model for your platform.
- Font not found — The font specified in
.spritefontmust be installed on the build machine. Use a bundled.ttffile path instead. - Model appears all white — The model’s textures were not found relative to the
.fbxfile. Place textures in the same folder or adjust the path in the MGCB Editor.
Content build output
dotnet mgcb Content/Content.mgcb /rebuild
dotnet build
The content pipeline is one of MonoGame’s greatest strengths. Invest time in understanding it early — it pays off with faster load times and smaller build sizes as your project grows.