Modwright Services and pricing
Field notes

Porting a Forge 1.20.1 mod to NeoForge 1.21.1: what breaks quietly

Most of the errors in this move show up the moment you compile, and they are the easy part. The ones worth writing down compile clean, start the game without a warning, and only show up when somebody plays. These are the ones I hit.

Everything below comes from two real ports. Mindful Eating, camcam_burger's food-variety mod, which I took from Forge 1.20.1 to NeoForge 1.21.1 and handed back to its creator. And the NeoForge 1.21.1 version of Puppy Paws, a dog mod with five breeds on GeckoLib that I had already moved to Forge from its released jar.

1. The part the compiler handles for you

mods.toml becomes neoforge.mods.toml, and mandatory=true on a dependency becomes type="required". Registration moves to the NeoForge DeferredRegister helpers. The resource pack_format goes from 15 to 34. None of this is hard, and the build tells you where every piece is.

GeckoLib is the one that looks scarier than it is. Version 4.8.3 exists for both, but in 1.21.1 the core package is flattened: core.animation is now animation, core.animatable is now animatable, and CoreGeoBone becomes cache.object.GeoBone. The models, renderers and animation calls keep the same signatures. It is a long list of imports, not a rewrite.

2. Data folders were renamed, and a wrong name fails silently

1.21 moved most data folders to singular: recipes to recipe, loot_tables to loot_table, advancements to advancement, tags/items to tags/item, tags/blocks to tags/block. Biome modifiers move from forge/biome_modifier to neoforge/biome_modifier, and "forge:add_spawns" becomes "neoforge:add_spawns". In a recipe, the result changes from {"item": ...} to {"id": ...}.

Miss one and nothing complains. The game skips a folder it does not recognise, so your recipes or your spawns are simply not there. I stopped trusting my memory for these and read the path from the decompiled sources instead: Registries.elementsDirPath gives the exact folder name for any registry.

3. Food is read from the stack now

This one cost me a heal that never happened. In 1.20.1 it was normal to shrink the stack first and ask for the food values after, because the values came from the item. In 1.21 they come from the stack. Once the last piece is eaten the stack is empty, the food values come back null, and the last bite does nothing. No error, no log line.

Two related changes from the dog mod: Animal#isFood is now abstract, so a base class that never overrode it stops compiling, and FoodProperties#isMeat is gone. The replacement for "meat a dog will eat" is the tag vanilla wolves use, ItemTags.WOLF_FOOD.

4. Methods that vanished from the parent stay in your code, dead

If you rebuilt a mod from its jar, as I did with Puppy Paws, the decompiled code has almost no @Override annotations. When a method disappears from the parent class, yours keeps compiling and is simply never called. getStandingEyeHeight was removed in 1.20.5 and is the classic one. The fix is boring. Go through every override against the 1.21.1 sources, one by one.

5. Some tags you relied on no longer exist

minecraft:music_discs was how the jukebox decided what it accepted. In 1.21 that job moved to a component, and vanilla neither defines nor reads that tag any more. A copied music_discs.json just sits there. Other mods ask through the convention tag c:music_discs, which NeoForge fills with the vanilla discs.

Discs themselves left the code. RecordItem is gone; a disc is a plain item with a jukebox_playable song, and the song is a JSON file with its sound, description and length in seconds. The old seconds-versus-ticks trap of 1.20.1 goes with it. The rule I took from this is that when you port, a tag is not carried over, it is looked up again.

6. Per-player data: capabilities become data attachments

Mindful Eating kept per-player state in a capability, through a library. Its creator suggested dropping that library, so I moved the state to NeoForge data attachments, which are built in, and the port no longer depends on it. Before sending the jar I checked it had no references left to the old library, because its licence does not allow bundling it. The food-stat tweaks moved to the 1.21 component system in the same pass.

7. How I check it without trusting my eyes

None of this replaces playing it. A dedicated server never loads a model or a texture, so a server that starts clean says nothing about the client.

If you would rather hand it off.

If your mod is on Forge 1.20.1 and you need it on NeoForge 1.21.1, send it to me. I check the licence first, tell you a fixed price before you pay anything, and you see it working in game before you pay the rest.

Get a quote Price your mod on Discord


What this costs. A version jump like this one is one of the walls I describe in what a mod port costs, and why. If the mod is on Fabric instead, start with what breaks in a Fabric to Forge port.

Written by danisansietev, Forge 1.20.1 mod porting. Last updated November 2026. Questions, corrections or a mod you need moved: open a ticket on my Discord.