Heavy modpacks have a reputation: beautiful for the first hour, a slideshow by the first village raid. It doesn't have to be that way — most "modpack lag" is three fixable problems stacked on top of each other.
1. Give the JVM a fighting chance
Default Java flags are tuned for web servers, not for a game ticking 20 times a second. Switching to ZGC with a fixed heap removes the GC spikes that cause those rhythmic half-second freezes.
java -Xms8G -Xmx8G -XX:+UseZGC \ -XX:+ZGenerational -XX:+AlwaysPreTouch \ -jar forge-server.jar nogui
2. Pregenerate your world
Chunk generation is the single most expensive thing a modded server does. Generating terrain while players explore is what turns 20 TPS into 6. Pregenerate a 5,000-block radius before opening the server and exploration becomes nearly free.
Rule of thumb: if your players can hit ungenerated chunks in under 30 minutes of walking, your pregen radius is too small.
3. Find the actual offender
Don't guess — profile. One misconfigured mod usually accounts for 60%+ of tick time. Run a Spark profile for five minutes of normal play and sort by self-time. The usual suspects: aggressive mob spawners, chunk loaders left running, and map mods rendering for offline players.
On Campfire, Spark ships preinstalled on every Forge and Fabric server — type /spark profilerin the console and we'll render the flame graph right in the panel.