Jun 08, 2026

ERP Module Dependency Management: How to Stop Breaking Things When You Add or Remove Modules

Adding or removing ERP modules shouldn't cause cascading failures. Here's how to think about module dependencies, what breaks silently, and how to manage it properly.

ERP Module Dependency Management: How to Stop Breaking Things When You Add or Remove Modules

You added a module. Everything looked fine. Then three weeks later a client calls because their inventory reports stopped showing landed costs. You dig in and realize the inventory module was pulling a computed field from a costing module you removed two sprints ago during a “cleanup.” Nobody noticed until month-end.

This is the most common silent failure mode in ERP systems, and almost nobody talks about it directly. Module dependency management sounds boring. It’s actually the difference between an ERP that you can confidently evolve and one that becomes increasingly fragile with every change.

Why Module Dependencies Are Harder Than Package Dependencies

When you’re managing Python packages or npm libraries, dependency management is well-understood. You have a lockfile. Your package manager tells you when something conflicts. You get an error at install time, not at runtime three weeks later.

ERP module dependencies don’t work like that. The failure modes are different and often much worse:

  • A module removal silently drops a database field that another module was reading
  • Two modules both try to extend the same model and the order they load in produces different behavior depending on the environment
  • A module that “doesn’t touch” your CRM still registers event listeners on customer records and breaks when it’s gone
  • Frontend views render fine but computed totals are wrong because a pricing module’s hooks are no longer firing

The problem is that ERP modules aren’t just code packages. They’re packages that mutate shared state: database schema, model behavior, UI layouts, permission trees, and background job queues. When you remove one, you’re not just removing code. You’re potentially changing all of those things at once.

The Four Types of Module Dependencies You Need to Track

Most teams think of dependencies as “Module A needs Module B to be installed.” That’s the obvious kind. But there are three others that bite you more often.

Hard dependencies are the obvious ones. If your accounting module requires a currency module to function, that’s explicit and should fail loudly at install time if the dependency isn’t present. These are usually easy to define and enforce.

Soft dependencies are sneakier. Module A works without Module B, but certain features degrade silently. If you have a CRM module and a marketing automation module, your CRM might work fine without marketing, but the “last campaign engagement” field just shows blank with no warning. That’s a soft dependency and it’s easy to miss in testing.

Behavioral dependencies happen when one module registers hooks, signals, or event listeners on models owned by another module. The owning module doesn’t know about it. The dependent module doesn’t declare it explicitly. It just wires itself into the system at startup. Remove the dependent module and the hook is gone. Remove the owning module and the hook fires into nothing or throws errors.

Schema dependencies are the most dangerous. One module adds a computed field or a foreign key that another module reads directly from the database without going through the ORM. If the source module is removed and the field disappears, the query breaks at runtime. In production. For real users.

If you’re not tracking all four types, you’re flying blind.

How to Audit What Your Modules Actually Depend On

Before you can manage dependencies properly, you need to know what you have. This is not a one-time exercise. It should be something you revisit whenever you add, modify, or plan to remove a module.

Start with the obvious: look at your explicit dependency declarations. Every module should have a manifest or configuration that lists what it requires. If yours don’t, that’s the first thing to fix. Modules that don’t declare their dependencies are ticking clocks.

Then go deeper. For each module, ask:

  • Does this module extend any models it doesn’t own? Which fields does it add? Which modules own those models?
  • Does this module register any event listeners, signals, or hooks on external models?
  • Does this module read any fields it didn’t create? Where do those fields come from?
  • Does this module add any foreign keys that point to tables owned by other modules?
  • Does this module contribute anything to shared UI components like dashboards, reports, or nav menus?

This is tedious work the first time. But once you’ve done it, you have a real dependency map, not just the declared one. And you’ll find things that surprise you.

The modular ERP architecture guide covers the structural reasons why this matters at the architecture level. Dependency management is the operational practice that makes modular architecture actually work in production.

What Happens When You Skip Dependency Checks on Removal

Let’s be specific about the failure scenarios because “things break” isn’t useful.

Schema orphaning. A module is removed and its database tables or columns are dropped. Another module had a raw query or ORM filter that referenced those columns. The query now throws a database error. If you’re lucky, it throws loudly. If you’re unlucky, it silently returns an empty result set and someone wonders why their data disappeared.

Broken computed values. Computed fields often depend on data from multiple modules working together. Remove one module and the computation either fails or silently returns a wrong value. This is particularly nasty in accounting and inventory where wrong-but-not-zero numbers can propagate through reports before anyone notices.

Permission tree corruption. If your permissions system is built on a hierarchical model where modules contribute roles and permission nodes, removing a module mid-setup can leave orphaned permission assignments. Users might lose access to things they should have, or worse, retain access to things they shouldn’t through stale assignments.

Background job failures. Modules often register scheduled tasks or queue workers. Remove a module and the job definition is gone, but if you have queued items already waiting for that worker, they’ll fail repeatedly until you manually clean up the queue. At 3am. On a Sunday.

Frontend rendering errors. If your frontend views are dynamically composed from module contributions (which in a well-built ERP they should be), a removed module might leave a view template referencing a component or data field that no longer exists. The YAML-based form rendering approach helps here because view definitions are explicit. But it only helps if you’ve also cleaned up the YAML when you removed the module.

Building a Safe Module Removal Process

Here’s the process that actually works. It’s more steps than you want, but skipping steps is how you get 3am phone calls.

Step 1: Run a dependency scan before you remove anything. You need to know what depends on the module you’re removing. Check both declared dependencies and the behavioral/schema ones you mapped earlier. If anything depends on it, you have two choices: fix those dependencies first, or remove both modules together in a coordinated way.

Step 2: Check for active data. If the module being removed owns any tables, check whether those tables have data in them. An empty table is fine to drop. A table with 50,000 records is a conversation you need to have before you touch anything.

Step 3: Deprecate before you remove. For anything but a brand new installation, the right move is usually to deprecate a module first. Leave it installed but disabled. Fix all the things that were depending on it. Run in that state for at least one full business cycle. Then remove it.

Step 4: Remove in the right order. If you’re removing multiple modules at once, order matters. Remove dependent modules before the modules they depend on. Removing in the wrong order causes cascading failures that are harder to diagnose because multiple things are broken at the same time.

Step 5: Verify schema state after removal. After removing a module, explicitly check that your schema is in the state you expected. No orphaned foreign keys pointing to dropped tables. No indexes referencing non-existent columns. No views or triggers that reference removed tables.

Step 6: Run your full test suite, not just the tests for the affected modules. A module removal can break things in unexpected places. Your tests need to cover cross-module behavior to catch these issues.

This connects directly to the points in the ERP testing strategy post about why cross-module integration tests are so important. Unit tests per module won’t catch dependency failures. Only integration tests that exercise the system as a whole will.

Designing Modules to Be Removable From Day One

The best time to think about removal is when you’re adding a module, not when you’re trying to take it out six months later.

A few practices that make modules much safer to remove:

Don’t cross module boundaries with direct field references. If Module B needs data from Module A, it should go through a defined interface, not by directly querying Module A’s tables or accessing model attributes that Module A added. When Module A is eventually removed, you have one clean place to update, not a dozen scattered references.

Make behavioral hooks safe when the dependency is absent. If your module adds a hook to another module’s model, write it so that it checks for the dependency at runtime rather than assuming it’s always there. A hook that fails gracefully when its dependency is missing is much easier to deal with than one that throws exceptions in production.

Declare soft dependencies explicitly. Even if a module works without something, declare that the optional dependency exists and what features degrade without it. This gives you a clear inventory and gives future developers a warning before they remove something.

Keep your module’s schema self-contained. Minimize foreign keys that point to tables owned by other modules. Where you need them, make sure they’re nullable so that removing the referenced module doesn’t orphan your records.

Version your module interfaces. If other modules depend on yours through a defined interface, version that interface. Breaking changes in one module should be explicit, not discovered accidentally.

The Performance Angle Nobody Mentions

There’s a performance reason to care about this beyond just correctness.

ERP systems accumulate modules over time. Most installations have modules that are partially used or installed “just in case.” Every module you have installed has a startup cost. It registers its hooks, loads its configuration, potentially adds indexes and query overhead even for operations that don’t use it at all.

If you have 15 modules installed and 6 of them are barely used, you’re paying a runtime cost for all 15 on every request. The hooks those 6 modules registered are firing on every relevant model operation. Their permission nodes are being evaluated in every access check.

Keeping your module footprint lean isn’t just about cleanliness. It’s a performance decision. And if you’ve read the ERP performance tuning guide, you know that the cheapest optimization is eliminating work you don’t need to do in the first place.

Modules you don’t need but haven’t cleaned up are a tax you pay on every operation, forever.

Handling Dependency Conflicts When Adding New Modules

Addition has its own problems. When you’re adding a new module to an existing installation, you can run into conflicts that are just as painful as removal failures.

Model extension conflicts happen when two modules try to add a field with the same name to the same model. If you’re using a proper extension mechanism (not monkey-patching), this should fail at load time. If you’re not, it silently overwrites one with the other and you get inconsistent behavior depending on load order.

Permission namespace collisions happen when two modules register permission nodes with the same identifier. Your access control system now has ambiguous rules and the behavior depends on which module loaded first.

Background job ID conflicts happen when two modules register jobs with the same name or queue. Tasks meant for one module get picked up by workers from the other.

The solution to all of these is the same: modules need namespaced identifiers for everything they register globally. Field names, permission nodes, job identifiers, event names. If your module’s contributions to shared systems are namespaced by module, conflicts become impossible instead of just unlikely.

Conclusion

Module dependency management isn’t glamorous work. There’s no exciting new feature to ship at the end of it. But it’s the kind of foundational work that determines whether your ERP stays maintainable as it grows or slowly turns into something nobody wants to touch.

The three things that matter most:

  1. Know your real dependencies, not just your declared ones. Behavioral and schema dependencies are where the silent failures live.
  2. Build modules to be removable from the start. Clean interfaces, namespaced identifiers, and graceful degradation make future changes dramatically safer.
  3. Treat module removal as a migration, not a delete operation. Deprecate, verify, test, then remove.

Fullfinity’s modular architecture is designed around these principles. Because we’ve built systems where none of this was thought through, and we know exactly what that costs. If you want to see how the module system works in practice, explore the platform overview or browse the full blog for more on building ERP systems that hold up under real-world conditions.

More articles

View all
ERP Multi-Client Deployment: How to Manage Multiple Instances Without Losing Your Mind
17 Jun, 2026

ERP Multi-Client Deployment: How to Manage Multiple Instances Without Losing Your Mind

Managing multiple ERP instances across clients is messy. Here's how to structure your deployments, handle per-client customizations, and stop reinventing the wheel every time.

Read more
ERP Performance Tuning: What to Actually Optimize Before You Have a Problem
14 May, 2026

ERP Performance Tuning: What to Actually Optimize Before You Have a Problem

A practical guide to ERP performance tuning for developers and consultants. Learn what to actually optimize, when to optimize it, and how to avoid the common mistakes that slow systems down.

Read more
ERP Onboarding for New Clients: How to Set Up a New Instance Without Starting From Scratch Every Time
05 May, 2026

ERP Onboarding for New Clients: How to Set Up a New Instance Without Starting From Scratch Every Time

Every ERP consultant knows the pain of setting up a new client instance. Here's how to build a repeatable onboarding process that doesn't waste weeks of your time.

Read more