Back to Blog
Technical
January 5, 2025
7 min read

Microservices vs Monolith: Choosing the Right Architecture

Stop cargo-culting microservices. Most projects should start with a monolith—here's when that changes and when it doesn't.

Noam Favier
Developer & Founder
Microservices vs Monolith: Choosing the Right Architecture

Microservices vs Monolith: Choosing the Right Architecture

Everyone wants to talk microservices. Few people need them.

I've built tools that are single-binary executables (Sysmon-CLI, Iris) and tools that manage multiple repos (Zvezda). The pattern is clear: start simple, add complexity only when forced to.

Just Use a Monolith

Seriously. One codebase, one binary, one deployment. No service mesh, no distributed tracing nightmare, no "which version of the API contract are we on?"

The wins are obvious:

  • **Call a function**, don't make an HTTP request
  • **Stack traces** that actually make sense
  • **Transactions** that don't require distributed coordination
  • **One thing to deploy**, one thing to monitor
  • When you're a solo dev or small team (< 10 people), microservices are pure overhead. You're solving organizational problems you don't have.

    When Microservices Actually Make Sense

    Okay, sometimes you do need them. Not "we read about them on Hacker News" need them—actually need them.

    **Wildly different scaling needs.** Your image processing service needs 50 boxes, your API needs 3. Split them. Otherwise you're scaling everything to match your hottest service.

    **Team independence.** You have 5 teams and coordination is killing velocity. Fine—give them separate deploys. But you better have actual teams first, not 3 people LARPing as Netflix.

    **Failure isolation.** If your billing service crashing takes down your entire platform, that's bad. But most services don't need this level of isolation—a good process supervisor works fine.

    **Different tech stacks.** Rarely justified, but sometimes your ML team really needs Python and your API really needs Go. More often it's just resume-driven development.

    The Modular Monolith Compromise

    Before you split into microservices, try this: build a monolith with clean module boundaries.

    Zvezda does this—it's one binary, but the Git operations, search indexing, and CLI are separated by interfaces. If I needed to scale Git operations independently (I don't), extraction would be straightforward.

    Same with Iris: the model inference, API server, and context management are distinct modules. Still one binary. Still fast.

    What "Microservices" Really Costs

    Let's be honest about the tax:

    **Network calls everywhere.** Every function call is now a network request with serialization, retries, timeouts, and circuit breakers. Your p99 latency goes to hell.

    **Distributed state.** Transactions are now sagas. Debugging is now log correlation. Your simple bug is now a distributed systems puzzle.

    **Operational complexity.** Kubernetes, Istio, Jaeger, Prometheus, Grafana, alert managers, log aggregation... each one is a maintenance burden.

    **Development velocity.** Want to change something across two services? That's two PRs, two deploys, and coordination overhead. Refactoring becomes archaeology.

    I've seen teams spend more time managing their service mesh than actually shipping features. That's not a win.

    My Decision Tree

    **Solo or small team?** Monolith. Not even a question.

    **Medium team (10-30)?** Modular monolith. Clean interfaces, testable boundaries, but don't pay the distributed tax yet.

    **Large team (50+)?** Probably microservices, but only where team boundaries genuinely matter. Most companies at this scale still over-split.

    **Unclear requirements?** Definitely monolith. You can't design good service boundaries until you understand your domain.

    Tooling for Either Approach

    For monoliths: keep your build fast, tests fast, and dependencies minimal. Sysmon-CLI compiles in under a second. There's no excuse for slow builds.

    For microservices: invest in observability from day one. Distributed tracing isn't optional—it's the only way you'll debug cross-service issues.

    For both: write boring code. The architecture shouldn't be the interesting part—the problem you're solving should be.

    Final Thoughts

    Microservices solve real problems for companies like Netflix and Amazon. You are probably not Netflix or Amazon.

    Build a monolith. Make it fast. Keep modules clean. When you hit actual scaling limits or team coordination problems, then split things out.

    And remember: the best architecture is the one that ships.

    ArchitectureMicroservicesSoftware Design