← Back to blog
December 10, 2025·5 min read

From idea to shipped SaaS without rewrites

StartupsProductExecution

“We'll rewrite it properly later” is the most expensive sentence in SaaS. It assumes the current code is throwaway. It rarely is. Here is how to ship progressively so you never need the rewrite.

Start modular, stay monolithic

The consensus in 2025 is clear: begin with a modular monolith. Not microservices. A single deployable with clean internal boundaries.

Structure your codebase into modules — /modules/billing, /modules/auth, /modules/notifications. Each module exposes a narrow public interface and hides its internals. Modules communicate through these interfaces, never by reaching into each other's database tables.

Use Domain-Driven Design bounded contexts from day one — not to build microservices, but to draw lines inside your monolith that could become service boundaries later. When load or team size demands it, extract a module using the Strangler Fig Pattern: a proxy routes traffic to either the legacy module or the new service while both coexist.

Contracts over code

The single biggest enabler of evolution without rewrites is treating API contracts as the stable surface that everything else can change behind.

  • Version from day one. URL-based versioning (/api/v1/) is the simplest and most widely adopted.
  • Backward compatibility is non-negotiable. Add optional fields, add new endpoints. Never remove or rename. Every breaking change forces consumers to rewrite their integration.
  • Contract testing. Tools like Pact validate that a new deployment does not break any existing consumer expectation. Automate this in CI.

When you later extract a module into a separate service, the contract stays the same — only the transport changes from in-process calls to HTTP or gRPC.

Ship dark, release bright

Feature flags decouple deployment from release. Merge incomplete features behind a flag, eliminating long-lived branches and merge hell.

The rollout sequence: off → internal team → 5% of users → 25% → 50% → 100%, with monitoring at every stage. Rolling back from 5% affects 5% of users. Rolling back from 100% is a fire drill.

You do not need LaunchDarkly on day one. A simple feature config or environment variable toggle is enough. Graduate to a proper flag service when you have multiple environments or more than twenty flags. But treat every flag as temporary — each one gets an owner and an expiry date. Stale flags become hidden debt.

Earn your abstractions

Most rewrites trace back to over-engineering the first version. The antidote is the Rule of Three: write it once, copy it the second time, and only extract an abstraction on the third occurrence — when you have three concrete examples to inform the right generalisation.

A wrong abstraction is far more expensive than duplicated code. Every new requirement must be shoe-horned into the wrong shape. When you feel the urge to abstract, ask: do I have three different use cases for this? If not, copy-paste and move on.

The progression

At no point do you stop and rewrite. Each stage builds on the previous one:

  • Validate (weeks 1–4). Thinnest slice that proves the core value. Monolith, single database, no premature abstractions. Ship behind a flag to a closed beta.
  • Stabilise (months 2–3). Harden core paths. Add contract tests. Introduce structured logging. Still a monolith, but modules have clear boundaries.
  • Scale selectively (month 4+). Identify the module under the most load. Extract it behind the same API contract using Strangler Fig. Canary deploy at 5% before cutting over.
  • Mature (ongoing). Blue-green deployments, automated contract testing in CI, progressive rollouts, and pruning stale flags.

The bottom line

The architecture evolves with the product. Modular boundaries, stable contracts, feature flags, and earned abstractions mean you never need the big-bang rewrite. You just keep shipping.