Modular vs Monolith for AI Coding. Which is better?

September 26, 2025

Ross Ross Gerring

If codebases were kitchens, a monolith is one giant drawer that holds every utensil. Everything is technically “there,” but you spend ages rummaging, you cut yourself on a stray mandoline blade, and dinner is late. A modular codebase is a set of clearly labeled drawers and bins. You still have one kitchen, but each tool has a home. AI coding agents thrive in the second kitchen.

What do we mean by “monolith,” “modular,” and “microservices”?

  • Monolith: one deployable application where different concerns are tangled together. Often this shows up as huge files and long functions that know too much about everything else.

  • Modular (or modular monolith): still one deployable app, but internally split into neat modules with clear contracts. Think “one house, many rooms, doors between them.” This is a great default for most teams and a sweet spot for AI agents. See the “modular monolith” literature for patterns and benefits. kamilgrzybek.com

  • Microservices: many separately deployable services that talk across the network. This is a system architecture choice rather than a code-structure choice. It can help at scale, but it adds operational cost and new failure modes. Use it when you truly need independent deployment and scaling, not as a reflex. martinfowler.com

How they compare for AI and vibecoding

LLMs reason locally. They do best when you give them small, cohesive files, clear interfaces, and tests that act like bumpers at a bowling alley. Modular code reduces the “blast radius” of any change, which in turn reduces the number of hallucinated edits, broken imports, and side effects. A monolith is like a bowl of spaghetti: pull one noodle and the whole bowl moves.

Signs your codebase has drifted into monolithic territory

  • Giant files: 1,000 lines is common, 5,000 lines is a smell.

  • Do-everything functions: 100+ line functions with deep nesting.

  • Cross-cutting imports: modules reach into each other’s internals.

  • Brittle edits: change in one place breaks three others.

  • AI agents flounder: the model needs multiple attempts to fix a bug or it keeps touching unrelated code.

If you are seeing these symptoms, the problem is not your agents’ “intelligence,” it is the shape of the haystack you are asking them to search.

Unless guardrails are in place, do not assume AI coding agents will avoid monoliths or other bad practices. Most models will happily add one more helper to the already-huge file, because that is the path of least resistance. The fix is to make the easy path the right path.

Where microservices fit

Microservices can be the right choice when independent deployability and team autonomy outweigh the overhead of network calls, versioning, and distributed monitoring. Many teams start with a modular monolith and move selected modules out using a strangler fig approach: carve off one capability at a time behind a stable interface. martinfowler.com


Assuming modular is better for AI: how to get there

1) Refactor the monolith (what “refactor” means and how to do it)

Refactor means changing the internal structure of code to make it cleaner and safer without changing its external behavior. You keep the kitchen, but you reorganize the drawers.

A practical, AI-friendly plan:

  1. Draw the map: generate a dependency graph to see tight clusters and cycles. Tools like dependency-cruiser help you spot tangles quickly. GitHub

  2. Choose seams: pick one feature area and introduce a tiny public interface for it.

  3. Extract modules: move code behind that interface into its own folder or package. Keep functions under 80 lines and files under ~400 lines. Enforce this with ESLint’s size rules. eslint.org

  4. Add tests around behavior: snapshot tests and a few happy-path flows prevent accidental behavior changes during moves.

  5. Repeat in small steps: several small PRs beat one mega-PR.

  6. Consider the strangler fig pattern for bigger rewrites: route calls through a facade, then swap implementation behind it when green. martinfowler.com

Using GPT-5-Codex effectively: ask it to

  • propose a module decomposition for a specific file,

  • draft a migration plan with diffs in small steps,

  • add minimal contract tests,

  • and run lints plus dependency checks, fixing only the findings.

2) Introduce guardrails so the code stays modular

Make monoliths impossible to commit:

  • Lint limits: ESLint max-lines and max-lines-per-function rules; set strict thresholds and fail CI on violations. eslint.org

  • Dependency rules: block cycles and illegal cross-layer imports with dependency-cruiser in CI. GitHub

  • Decision log: record architecture choices in simple ADRs so future contributors and agents know the intended boundaries. Architectural Decision Records

  • Folder contracts: document “public” entry points per module and forbid “deep imports.”

  • Small PR policy: cap PR size and require a passing test for each new public API.

  • Scaffolds: supply templates for new modules so the path of least resistance produces the right files in the right places.

  • Monorepo with modules: if helpful, use a toolchain that encourages separate packages within one repo, but keep one deployment until you actually need microservices.


Where this is heading

It is in everyone’s interest for vibecoding tools to bake in best-practice rails: structure-aware edits, automatic ADR updates, enforced size limits, and built-in dependency checks. Expect future agents to come with “modularity by default” and to negotiate changes with your rules before touching code. Until then, a few lightweight guardrails will do most of the work.


Glossary

  • Monolith: one deployable application where concerns are intertwined.

  • Modular monolith: one deployable app with clean internal modules and contracts. kamilgrzybek.com

  • Microservices: many independently deployable services that communicate over the network. martinfowler.com

  • Refactor: change the internal structure without changing external behavior.

  • Strangler fig pattern: gradually replace parts of a system behind a facade, one slice at a time. martinfowler.com

  • ADR (Architecture Decision Record): short document capturing a significant technical decision and why it was made. Architectural Decision Records

  • Dependency graph: a map showing which modules import which others, useful for spotting cycles and tight coupling.

  • Cycle: a loop in dependencies that makes modules hard to test or replace.

  • Guardrails: automated rules and checks that keep a codebase healthy by preventing risky changes from merging.


Further reading