Industries - Software Development

Build or Buy Software? The CTO’s Break-Even Test

A CTO choosing between a SaaS product and an in-house application is rarely choosing between two feature lists. The real choice is who will control the rules when an ordinary transaction becomes an exception. My default is to buy the repeatable transaction and build only the decisions that change often enough, or matter enough, to justify owning them.

Buy the repeatable transaction; build the changing decision

The two approaches are a configured SaaS product and an in-house application. SaaS wins when the process can follow a stable product model: people submit requests, authorized people approve them, and the resulting records move to another system. Its price includes subscription fees, configuration, integration, and dependence on the vendor’s release schedule. An in-house application wins when the organization’s own rules determine what happens next and those rules change faster than the vendor can accommodate them. Its price includes delivery, security, support, and every later change.

I would not fund a custom application merely because a team dislikes a vendor’s screens, because an inconvenient interface is cheaper to work around than an application is to operate for years. Conversely, I would not buy a product that requires staff to re-enter decisions in a spreadsheet, because that workaround becomes an untested second system of record. Both positions need evidence from the actual workflow, not a polished demo or a developer’s preferred stack.

I would set aside Angular in 2026 What advice is now wrong for CTO buy vs build during the first funding discussion, because the frontend framework cannot establish whether a vendor will accept the organization’s exception rules. Angular v20 may be a sound implementation choice for a team that already supports it, but it cannot settle the ownership decision. That decision starts with a boundary: which system records the authoritative outcome, and which system can change it?

Consider an approval that normally needs one manager but needs a second reviewer when a contract has a particular clause. If that clause is rare and stable, vendor configuration may be sufficient. If legal staff revise the interpretation every month and must explain each decision to an auditor, an internally owned rules service may be worth building. That does not require rebuilding the vendor’s intake, notifications, and identity management. Buying the routine path while building a small decision component is still a buy decision for most of the workflow.

Set a change horizon before selecting either option. A proposed rule that must be deployed within 2 business days is a target to validate with the process owner, not proof that SaaS cannot work. Ask the vendor to demonstrate the change in a test tenant, and ask the internal team to estimate its own lead time. Whichever approach can meet the target repeatedly, with an attributable record of who changed what, has earned consideration.

An exception ledger reveals costs that a feature checklist hides

A feature checklist records whether a product can approve, route, and export. An exception ledger records the cases that make those verbs expensive. Take a sample of completed work, then log the trigger, the human decision, the data consulted, the system updated, and the time spent recovering when the normal path failed. Include cases that were abandoned or resolved by email; a ticket queue alone will miss work that nobody thought to report.

I would use Enhancing Business Operations Through Custom Applications to identify candidate process changes, but I would not treat a plausible efficiency gain as permission to build, because the savings depend on how often the troublesome case occurs. A custom rule that saves a minute once a quarter is unlikely to repay its support burden. A rule that prevents repeated, consequential corrections might.

For each candidate workflow, measure completed volume, exception rate, handling time, and the cost of an incorrect outcome. Suppose a four-week pilot records 18 minutes of manual handling per exception; that is a measured pilot result only if someone timed the work, not an estimate from a meeting. Compare it with a separately recorded baseline after the pilot, since a faster test environment can conceal production delays. Set an initial 2% exception-rate threshold as a value to tune: below it, investigate whether a manual queue is simpler; above it, test whether automation removes enough recurring work to justify its controls.

Do not count every exception as evidence for building. Some occur because fields are unclear, and a better form in the purchased product may eliminate them. Others involve a judgment that should remain with a person, even if an in-house system could encode it. Classify each case as preventable by configuration, suitable for a documented human decision, or suitable for a changeable rule. The classification matters because a high exception count caused by poor input design calls for a different investment from a high count caused by complex policy.

Run the same cases through both approaches. In the SaaS trial, configure the real approval rule and attempt a policy change without vendor assistance. In the in-house prototype, implement the rule, its audit record, and a correction path; do not stop at a screen that produces the right answer once. If neither can show who made a decision and which rule version applied, neither has passed the trial. That test gives the CTO a narrower, more defensible scope than “build an operations platform.”

Buying wins only when its integration and exit terms are workable

A vendor demo proves that a workflow can run in the vendor’s environment. It does not prove that the organization can retrieve its data, reconcile failed transfers, or leave the product. Before signing, request a working export containing records, attachments, identifiers, timestamps, and audit events. Import that export into a test database such as PostgreSQL 16. If the vendor cannot supply the relationships needed to reconstruct a case, the apparent speed of buying comes with an exit cost that belongs in the comparison.

Check interfaces by exercising them, not by counting API endpoints. OpenAPI 3.1 can describe request and response shapes, but a useful trial also tests pagination, rate limits, retries, and behavior after a timeout. If the vendor sends webhooks, ask whether events can arrive twice or out of order, then use idempotency keys or stored event IDs to prevent duplicate actions. If the vendor cannot identify a durable event ID, a nightly reconciliation job may be necessary, because a successful HTTP response does not prove every downstream record arrived.

Identity and access deserve the same practical test. Try the organization’s OpenID Connect login, then remove a test user and verify that access ends as expected. If automated provisioning is required, test SCIM 2.0 rather than accepting a statement that it is supported. Review the vendor’s SOC 2 Type II report for the relevant service and period, but do not mistake the report for proof that the organization’s own roles and retention settings are correct. Those remain configuration decisions the buyer owns.

Use service terms as inputs to an operating plan. A vendor-published 99.9% uptime SLA, if offered, permits roughly 43 minutes of downtime in a 30-day month before its availability threshold is crossed. That figure says little about a broken export or an approval stuck for hours, so define an internal service-level objective for the complete workflow. Measure p95 time from submission to an attributable outcome with OpenTelemetry traces and a Grafana dashboard, including any in-house components and reconciliation jobs.

These tests can make SaaS the clear winner: reliable exports, usable APIs, and acceptable administration let a small team avoid owning a commodity application. They can also reveal a reason to build a narrow component: the vendor may handle intake well while withholding the rule history needed to explain decisions. Buying remains faster only when the integration contract supports the work that will happen after launch.

Fund the option that survives a change-horizon calculation

Compare the approaches over the period in which the workflow is likely to change, rather than over an arbitrary first-year budget. Here is an illustrative calculation, not a quote: SaaS has $40,000 in setup costs and $22,000 per month in subscription and internal operations; an in-house application has $240,000 in initial delivery costs and $9,000 per month in maintenance and infrastructure. At 12 months, the undiscounted totals are $304,000 for SaaS and $348,000 for the build. At 24 months, they are $568,000 and $456,000. The crossover occurs after about 16 months because the build starts $200,000 behind but costs $13,000 less each month.

Discount future spending if timing matters to the organization. The following Python 3 snippet runs as written; its monthly discount rate and costs are assumptions to replace with approved figures.

setup = {"saas": 40000, "build": 240000}
monthly = {"saas": 22000, "build": 9000}
rate = 0.01
for months in (12, 24):
    totals = {}
    for option in setup:
        totals[option] = setup[option] + sum(
            monthly[option] / (1 + rate) ** month
            for month in range(1, months + 1)
        )
    print(months, {k: round(v) for k, v in totals.items()})

The crossover is not an automatic instruction to build, because the cheaper projection assumes the internal team can deliver and maintain the application at the stated cost. Add a range for security fixes, staff turnover, and changes to upstream APIs. Add a range for vendor price increases and paid integration work on the SaaS side. Then test the decision against the likely lifetime of the rule: if the workflow may be retired in a year, the build cannot recover its upfront cost in this example. If it is likely to remain for several years and its rules require frequent, controlled changes, ownership may be cheaper and more responsive.

Require an executable acceptance test before approving either budget. Playwright can exercise a submitted case through its visible outcome, while a contract test can check that the resulting API record matches the OpenAPI 3.1 schema. Include a duplicate webhook, a revoked user, and a corrected decision in the test data, because ordinary happy-path submissions will not expose the costs identified in the exception ledger. Assign one owner to the end-to-end result even when the solution mixes purchased and built components; otherwise each party can declare its own part healthy while the request remains unresolved.

The first funding decision should be a bounded trial

Choose one workflow and pull its last month of completed and corrected cases. Ask the SaaS vendor to run those cases in a test tenant, and ask the internal team to prototype only the rule the vendor cannot express. Record handling time, failed transfers, rule-change lead time, and the ability to reconstruct each decision. Fund the approach that meets those checks within its change horizon, rather than the one with the better demonstration.