Contact
ProductOct 29, 2026·38 min read

Build vs Buy Software: When Buying Wins and When It Stops, With a Model You Can Run

KT
Keplaris TeamOct 29, 2026
Illustration of a half-built stack of glass cubes on a workbench beside a sealed cube in a black box, with a blue and a green line crossing between them

Build vs buy software is decided one capability at a time: build what customers choose you for, and buy what they never notice. Buying stays right while 36 months of the vendor's price costs less than building and running the capability. Building wins when no vendor meets a hard constraint, or when your scale pushes the vendor's price past that line.

To show where that line sits, we ran a small Node script on two public pricing pages read on October 29, 2026: Google Cloud Identity Platform for authentication and Amazon SES for transactional email. In our model, on assumed build hours, building auth on a maintained library pays off from 377,360 monthly active users at the mid estimate, 188,118 at low hours and 692,763 at high. Email stays cheaper to buy below 6,102,212 messages a month on all three of our build estimates. The script, its unedited output and every assumption are further down, so you can change them.

Keplaris is a New York product engineering studio that designs and builds SaaS products and APIs, so we get paid when companies build. That is why each number below comes from a public page or a stated assumption you can change. The model still says buy more often than build: buying was cheaper in 28 of the 42 cases it tested, each case a scale paired with a build estimate.

Build vs buy software: what it means, the four options and where partner fits

Build vs buy software is the choice between owning a capability, by writing and running it yourself or paying someone to write it for you, and paying a vendor for an existing product. It is also called custom software vs off the shelf, or a make or buy decision. It is made one capability at a time, not once for the whole product: sign-in, billing, email, search and the workflow customers pay for can each get a different answer.

There are four options for any one capability:

  • Build. Your team writes and runs it as custom software. In this post, building auth or email means assembling it on a maintained library, not writing your own password hashing or crypto.
  • Buy. You pay a vendor and adapt to its off-the-shelf product: an API, a hosted service or a SaaS tool.
  • Buy and extend. You buy a platform and add your own code on top, through its APIs, webhooks or extension points.
  • Self-host open source. You run someone else's code on your own infrastructure. You pay no license fee, but you carry the hosting, upgrades and on-call, so for cost purposes it sits close to building.

Most products end up hybrid: they buy the commodity layers and build the core.

"Build vs buy vs partner" adds a word with two meanings. A partner can be someone else who builds the capability for you, which is still building for cost purposes, because you own and maintain what they deliver. Or it can be a vendor platform you extend, which is buy and extend. Who does the build work, whether your own team, a studio or a freelancer, changes the rate in the formulas below but not the structure of the decision.

No-code tools are a separate choice, which we'll cover in its own post.

When to build vs buy software, with the pros and cons

The answer turns on three questions: is this capability why customers pick you, does any vendor meet your must-haves, and has your scale crossed the break-even? Martin Fowler put the split this way in his Utility vs Strategic Dichotomy (published 2010-07-29, updated 2016-04-07): "there are two kinds of software projects and they need to be treated entirely differently". His advice for the first kind is direct: "for a utility function you buy the package and adjust your business process to match the software". He also expects few projects to be strategic: "The 80/20 rule applies, except it may be more like 95/5."

Joel Spolsky made the build half of the same argument in 2001, in In Defense of Not-Invented-Here Syndrome: if something is a core business function, you should do it yourself, even when a vendor offers it.

Build when one of these is true:

  1. It is the reason customers pick you.
  2. No vendor meets a must-have. Data residency, a compliance rule or a required integration that no product supports.
  3. The vendor's price at your scale has crossed the cost of owning it, and you expect to stay above that line.

Buy when one of these is true:

  1. No customer would notice you built it.
  2. Time to market matters more than the 36-month cost. Before revenue, weeks usually beat dollars.
  3. Nobody on your team should be running it at 3 a.m. Auth and email both page someone when they break.

Fowler adds the line that keeps this from becoming dogma: "This is not a static dichotomy." A capability that is strategic today can become a utility, and a utility can become core as the product changes. The buy vs build rule, in one sentence: buy what your customers would never choose you for until the vendor costs more than owning it, and build what they do choose you for.

The build vs buy software pros and cons, in short, drawn from the sections below:

ProsCons
BuildFits your must-haves, no vendor repricing or acquisition risk, cheaper than the vendor past the break-even at scaleMaintenance, on-call and patching for as long as you run it, build time that comes out of your launch weeks, key-person risk
BuyFaster to market, the vendor carries security patching and email deliverability, free or cheap at small scalePrices, plans and units can change after you integrate, the vendor's outages become yours, integration and exit cost

Which parts of a SaaS product to buy

For most SaaS products, buy every layer except the workflow customers pay for, and revisit each default when its flip condition arrives. If no customer would notice you built it, buy it.

LayerDefaultWhyWhen the default flips
AuthenticationBuySecurity-critical, well-solved, and free at small scale on some vendorsYour vendor bill crosses the break-even below, or a compliance rule rules vendors out
PaymentsBuyCard networks, fraud and PCI scope are a business on their ownRarely; at most you add a second processor
Subscription and usage billingBuyProration, tax and invoicing edge cases pile up fastYour pricing model is the product; see our usage-based billing guide
Transactional emailBuyDeliverability is reputation work, not codeMillions of messages a month, and a team that already runs mail servers
File storageBuyObject storage is priced per gigabyte and hard to beatData residency or on-premises customers
Error monitoringBuyValue comes from the tooling around the dataData you cannot send to a third party
SearchBuyRelevance tuning is a specialist jobSearch quality is what customers pay for
Feature flagsBuy, or a simple table at firstA few flags fit in your database; targeting rules and audit trails don'tRarely
Internal automationBuy, then rebuild the workflows that outgrow itOff-the-shelf tools prove a workflow cheaply; our workflow automation guide says "both are right, for different workflows"Volume pricing or complex branching
The core workflowBuildIt is why customers choose youRarely; buy and extend only if the platform does not cap your roadmap

Of the ten top-ranking results we examined on October 29, 2026 for "build vs buy software", we read eight (one returned 403 and one we did not open). Neontri lists commodity functions to buy, such as payments, authentication and email, but none of those eight gives a default for each layer of a SaaS product with the condition that flips it. Most are written for enterprise IT or internal tools.

The buy list also covers back-office tools such as CRM, help desk and analytics. The table holds no vendor names on purpose: the layer vendors in this post appear only as model inputs or as examples of hidden costs and export terms.

Build vs buy analysis: how to calculate total cost of ownership

A build vs buy analysis compares 36 months of owning a capability against 36 months of paying for it, never a build quote against a monthly price. The two formulas, in words:

  • Buy = the subscription at your scale times 36 months, plus integration, migration, admin time and the cost of leaving.
  • Build = build hours times a loaded hourly rate, plus maintenance hours times the rate times 36 months, plus hosting, plus the services the build still buys (a self-built sign-in still sends reset emails and texts).

Why 36 months: year one hides maintenance, because the build cost lands up front and the upkeep has barely started. Five years stretches the price assumptions too far: SES moved new accounts to a different default plan in July 2026, as the hidden-costs section shows.

The loaded rate multiplies every build-side hour, so start there. Our SaaS MVP cost guide grosses up the BLS median developer wage for benefits: "one median-wage developer costs about $194,000 a year before recruiting fees, equipment, or a single shipped feature." Divided by 2,080 paid hours, that is $93.27 an hour, the rate our script uses. The same guide gives maintenance as "15-25% of build cost per year", and says so plainly: "It's a planning heuristic, not a measured figure."

Cost statistics we could not trace

Three numbers appear on build vs buy pages we read, and we could not trace a primary source for any of them:

  • Untraced, attributed to Forrester. Several pages claim that 67% of software projects fail because of the wrong build or buy choice, but none we read names or links a Forrester report.
  • Untraced, attributed to Gartner. One ranking page claims that hidden costs raise SaaS total cost of ownership by 150-200%, citing a Gartner report we could not trace.
  • Unsourced. Another page claims that a wrong decision costs 2-5x over 3-5 years, and gives no source.

That doesn't make them false. It means we couldn't check them, so we didn't use them.

Is it cheaper to build or buy? What our break-even model shows

On prices read October 29, 2026 and our assumptions, buying auth is cheaper up to a few hundred thousand monthly active users (MAU), and buying email is cheaper up to millions of messages a month. At 250,000 MAU, the modelled answer depends on your build-hour estimate, not on the vendor's price. The vendor costs $34,740 over 36 months, and building costs $24,492 at our low estimate and $55,831 at our mid estimate.

The model's build side covers both building on a maintained library and self-hosting open source, since both put the hours on your team. It uses these inputs. They are assumptions, not Keplaris data: we chose them to span a wide range, and none is measured from our projects.

InputLowMidHighBasis
Loaded hourly rate$93.27$93.27$93.27$194,000 a year divided by 2,080 paid hours. Paid hours, not productive ones, so it makes building look cheaper, which works against our own interest
Auth build hours (sign-up, sign-in, sessions, reset, social login, MFA, admin)80200400Assumption
Auth maintenance hours a month (patching, incidents, provider changes)41020Assumption
Email build hours (self-hosted sending, DNS authentication, bounce and complaint handling)40120240Assumption
Email maintenance hours a month (reputation, blocklists, queue health)81630Assumption
Hosting for the built option$100 a month (auth), $150 a month (email)samesameAssumption, held flat at every scale; not a vendor price

Auth: Identity Platform against a library build

Google Cloud Identity Platform's pricing page charges per monthly active user, defined as "Any account that has signed in within a given month". For email, phone, anonymous and social sign-in (its Tier 1), the first 50,000 are free, then $0.0055 each up to 100,000, $0.0046 up to 1,000,000, $0.0032 up to 10,000,000 and $0.0025 above. The script reproduces the page's own worked example (225,000 MAU costs $850 a month) before it runs. Phone sign-in and SMS multi-factor are also charged per message sent, which the model leaves out.

Modelled 36-month costs, prices read 2026-10-29. Building costs $24,492 at the low estimate, $55,831 at mid and $108,062 at high:

MAUVendor per monthVendor over 36 monthsCheaper at low / mid / high build
10,000$0$0buy / buy / buy
50,000$0$0buy / buy / buy
100,000$275$9,900buy / buy / buy
250,000$965$34,740build / buy / buy
500,000$2,115$76,140build / build / buy
1,000,000$4,415$158,940build / build / build

The modelled break-even, where 36 months of vendor cost equals 36 months of build cost, is 188,118 MAU at low hours, 377,360 at mid and 692,763 at high.

Transactional email: Amazon SES against self-hosted sending

Amazon SES charges $0.10 per 1,000 emails à la carte, plus $0.12 per GB of attachment data. Its Essentials plan charges $0.16 per 1,000 up to 10 million a month, $0.14 up to 100 million and $0.11 above, with no monthly plan fee. The page says those plan tiers apply marginally, to the emails within each tier. We used 32KB per message, the size SES uses in three of its four pricing examples.

Modelled 36-month costs, prices read 2026-10-29. Building costs $35,992 at the low estimate, $70,315 at mid and $128,515 at high:

Messages a monthSES planVendor per monthVendor over 36 monthsCheaper at low / mid / high build
100,000À la carte$10$374buy / buy / buy
100,000Essentials$16$590buy / buy / buy
1,000,000À la carte$104$3,738buy / buy / buy
1,000,000Essentials$164$5,898buy / buy / buy
10,000,000À la carte$1,038$37,382build / buy / buy
10,000,000Essentials$1,638$58,982build / buy / buy
50,000,000À la carte$5,192$186,912build / build / build
50,000,000Essentials$7,392$266,112build / build / build

The modelled crossing on Essentials is 6,102,212 messages a month at low hours, 12,188,579 at mid and 23,427,919 at high. À la carte moves it to 9,628,143, 18,809,757 and 34,378,581. Treat the high-volume build wins with suspicion: the model holds email hosting and maintenance flat at every volume, and both rise in practice.

Traced example: 800,000 MAU on auth

Take one illustrative consumer app (not a client) holding 800,000 MAU, all signing in by email or social login. The first 50,000 are free. The next 50,000 cost $0.0055 each, which is $275. The remaining 700,000 cost $0.0046 each, which is $3,220. That is $3,495 a month, or $125,820 over 36 months. Building at our mid estimate costs $55,831, so the vendor costs $69,989 more over 36 months, on our assumptions. At the high estimate ($108,062) the gap narrows to $17,758. If 5% of those users sign in through SAML, 760,000 Tier 1 users cost $3,311 and 40,000 Tier 2 users cost $599 at $0.015 each after the first 50, so the vendor bill rises to $3,910 a month and $140,769 over 36 months.

Sensitivity: SAML and productive hours

Two changes move the auth break-even, in opposite directions. Both are modelled on prices read 2026-10-29:

ChangeLowMidHighDirection
Base case: Tier 1 only, $93.27 an hour188,118377,360692,763
5% of MAU on SAML or OIDC at $0.015169,159339,181622,551Toward build, but build hours stay unchanged, and building SAML yourself would add hours, so this row flatters building
1,800 productive hours a year ($107.78 an hour)207,743426,423790,889Toward buy

Counting productive rather than paid hours raises every break-even, which is why the base case, built on 2,080 paid hours, leans toward building.

What this model does not prove

  • Build hours are assumptions. We have no measured build-hour data for these layers, and the sensitivity rows exist because of that.
  • Negotiated prices are outside it. Google Cloud's page invites you to request a custom quote; the SES page says "There are no contract negotiations and no upfront commitments."
  • Scale is held flat. Real products grow, so a product that will cross the break-even in year three looks different from one that sits there.
  • Opportunity cost is not priced, and for anything non-core it favours buying.
  • Deliverability and security risk are not priced. A breach or a blocklisted IP costs more than any row here.
  • One vendor per layer is a price point, not a market survey. The vendors are inputs, not recommendations.

The hidden costs of buying software

The hidden costs of buying come from the vendor changing what you pay, or what a unit means, after you've built around it. Price the unit before you price the plan: two auth vendors can count the same user differently.

  • Default plans change. SES footnote 3 reads: "New SES accounts and account x region combinations with no metered SES activity since June 1, 2025 will start on the Essentials plan beginning July 21, 2026." Essentials starts at $0.16 per 1,000 emails against $0.10 à la carte. The page says you can switch to à la carte at any time, but a new account that never checks pays the higher rate.
  • Units differ. Identity Platform counts any account that signed in that month. Clerk's pricing page counts monthly retained users instead: "A user is counted as retained when they return 24+ hours after signing up." Compare units before you compare prices.
  • The SSO step. Identity Platform charges $0.015 per SAML or OIDC user after the first 50. Clerk's Pro plan includes "1 SSO connection" and charges $75 a month each for connections 2 to 15 and $60 each from 16 to 100, and above 100 its table says "Contact us". One prices per user, the other per connection, so the cheaper one depends on how many enterprise customers you have and how big they are.
  • Acquisitions and shutdowns change the product. Kong announced its acquisition of OpenMeter, a usage metering platform, on September 3, 2025, and Kong now sells the hosted service as Konnect Metering and Billing, "powered by OpenMeter".
  • Their outage is your outage. A vendor incident takes your sign-in or email down with it, and the status page is theirs.
  • Integration work. Webhooks, retries, rate limits and data mapping take real engineering time. We know of no sourced percentage for it, so estimate it from your own integration count.
  • Exit. Leaving means exporting, re-integrating, re-testing and often running two systems in parallel; see the lock-in section below.

The hidden costs of building software

Building is a subscription you pay in engineering time. The build cost is the visible part; these are the rest:

  • Maintenance. The cost guide's heuristic is 15-25% of build cost a year. Our script prices maintenance as hours a month instead, so you can see it separately.
  • Engineering time. At the mid estimate, auth maintenance alone is 120 hours a year, about $11,200 at our $93.27 rate, before any build hours or hosting (modelled). That is more than the yearly vendor bill in three of the six auth rows above. Email's mid maintenance, 192 hours a year or about $17,900, is more than the yearly SES bill in five of the eight email rows.
  • Calendar. Our MVP timeline guide says "a real custom SaaS MVP, built by an experienced dedicated team, typically takes 10 to 16 weeks from kickoff to real users". Each commodity layer you build during an MVP comes out of those weeks.
  • On-call, incidents and security patching. These are the maintenance hours in our script, and they are assumptions.
  • Deliverability work if you send your own email. IP warm-up, DNS authentication, blocklist monitoring and bounce handling are ongoing, not one-off.
  • Key-person risk. A capability one engineer understands is a capability you lose when they leave.
  • Opportunity cost. Fowler on strategic work: "the biggest risk is not doing something before your competitors do." Hours spent on sign-in are hours not spent there.

Does AI-assisted coding change build vs buy?

AI lowers the cost to start, not the cost to own. In our model, treat the low build-hours case (80 hours for auth instead of 200) as a stand-in for an AI-assisted build and keep maintenance at the mid 10 hours a month. Build hours fall 60%, but the 36-month build cost falls 20%, from $55,831 to $44,638, and the modelled break-even moves from 377,360 to 309,774 MAU, 18% lower. Maintenance over 36 months is most of the build side, and AI does not remove the patching and incident hours.

Our cost guide covers where AI actually cuts the bill and the hidden AI tax, including the security pass rates and stability findings behind that caution.

A build vs buy decision framework: two gates, a scorecard, three scenarios

A build vs buy decision framework needs two gates before any scoring. If the capability is why customers pick you, build it or buy and extend it. If no vendor meets a hard constraint, build or self-host. Otherwise score both options from 1 to 5 on six weighted criteria and take the higher total. Two of our three scenarios come out as buy.

Weighted scorecards are already common on ranking pages (Zylo, Reflex and Neontri each publish one), so treat this as a method, not a discovery. The gates are what we add in front of the score.

  • Gate 1, differentiation. If the capability is the reason customers pick you, build it or buy and extend it. Stop scoring.
  • Gate 2, hard constraint. If no vendor meets a must-have (data residency, a compliance rule, a required integration), build or self-host. Stop scoring.

Then score each option from 1 to 5 on six criteria. Change the weights for your stage.

CriterionWeightWhy this weight
36-month TCO from the script30The one criterion with numbers behind it
Time to market20Before revenue, weeks matter more than dollars
Exit cost and reversibility15The cost of being wrong
Fit to must-haves15Gaps here become workarounds you maintain
Team capacity to run it, security included10Someone has to patch it and answer the page
Vendor risk (repricing, acquisition, shutdown)10The hidden costs above

For TCO, the cheaper option scores 5 if the other costs more than twice as much and 4 otherwise. The dearer option scores 1 above twice the cheaper one, 2 between 1.25 and 2 times, and 3 within 25%. Each total is the sum of weight times score, divided by 100.

Criterion (weight)A: buyA: buildB: buyB: buildC: buyC: build
36-month TCO (30)511542
Time to market (20)525352
Exit cost (15)343444
Fit to must-haves (15)444444
Team capacity (10)525352
Vendor risk (10)343434
Total4.352.503.154.004.202.80

Illustrative scenarios, not clients. B is scored at our mid build estimate, and C at our low build estimate against SES à la carte. The reasoning behind each score follows.

Illustrative scenario, not a client. A: B2B SaaS at launch, about 5,000 MAU, deciding auth. The vendor costs $0 a month on Identity Platform's free tier; building costs $24,492 at our low estimate. Buy: TCO 5, time 5, exit 3, fit 4, team 5, vendor risk 3, so (150 + 100 + 45 + 60 + 50 + 30) / 100 = 4.35. Build: TCO 1, time 2, exit 4, fit 4, team 2, vendor risk 4, so (30 + 40 + 60 + 60 + 20 + 40) / 100 = 2.50. Verdict: buy.

Illustrative scenario, not a client. B: consumer app holding about 800,000 MAU, whose engineers already run auth-adjacent infrastructure. The vendor costs $125,820 over 36 months against $55,831 to build at our mid estimate, more than twice as much. At mid hours, buy scores TCO 1, time 5, exit 3, fit 4, team 5, vendor risk 3, so (30 + 100 + 45 + 60 + 50 + 30) / 100 = 3.15. Build on a maintained library or self-hosted open source scores TCO 5, time 3, exit 4, fit 4, team 3 (security patching is now yours), vendor risk 4, so (150 + 60 + 60 + 60 + 30 + 40) / 100 = 4.00. At our high estimate ($108,062), the vendor costs 1.16 times as much, so the TCO scores become 3 for buy and 4 for build: buy 3.75, build 3.70. Verdict: build at the mid estimate. At the high estimate it is a near tie that leans buy, and staying put is the cheaper mistake to reverse. The answer turns on how honestly you estimate the hours.

Illustrative scenario, not a client. C: any product sending about 5 million transactional emails a month. SES à la carte costs $18,691 over 36 months; building costs $35,992 even at our low estimate. Buy: TCO 4, time 5, exit 4, fit 4, team 5, vendor risk 3, so (120 + 100 + 60 + 60 + 50 + 30) / 100 = 4.20. Build: TCO 2, time 2, exit 4, fit 4, team 2, vendor risk 4, so (60 + 40 + 60 + 60 + 20 + 40) / 100 = 2.80. On Essentials ($29,491), build's TCO score rises to 3 and its total to 3.10. Verdict: buy.

The honest limitation applies here too: the build-side TCO in each scenario rests on hour assumptions we did not measure.

How to buy without getting locked in

Before you sign, write down what leaving would cost, your switching cost, and score it as a factor. Of the ten top-ranking results we examined on October 29, 2026, we read eight (one returned 403 and one we did not open). Four of them discuss vendor lock-in, and two count switching costs inside total cost of ownership, but none gives exit cost its own weight in a scorecard. A data-ownership checklist:

  • Export format and completeness. For auth, ask: "Can I export password hashes and the hashing parameters, in what format, and does that cover every account?" Then check the answer in the vendor's docs before you sign. Clerk's migration docs describe a dashboard CSV export "that includes their hashed passwords". Firebase's auth:export docs say the command "only exports passwords hashed using the scrypt algorithm", and accounts hashed with other algorithms export with empty hash and salt fields. Without hashes, users have to reset their passwords, or you migrate each one as they next sign in.
  • Export API rate limits. A rate-limited export of a large user base can take a long time.
  • Deletion terms. Ask: "What happens to my data when I cancel, how long can I still export it, and when is it deleted?" Ask too whether you get a deletion certificate.
  • Renewal price caps and notice periods. On a contract, these set the price of staying another year. Ask: "If I sign a contract, how much can the price rise at renewal?"
  • Model-training clauses for AI vendors: whether your data trains their models, and whether you can opt out.

Own your IDs and keep your own source of truth. Our billing guide's rule applies to any layer you buy: "Keep your own ledger either way; a vendor holds a second copy of your usage data, not the first." An abstraction layer over the vendor's API is worth building where switching is likely, such as email, where a thin send function in front of the provider is cheap to write and cheap to repoint. Where switching is unlikely and the vendor's model shapes your data, as with auth, a wrapper is usually wasted work; spend the time on the export instead.

Questions to ask the vendor before you sign

Ask the vendor's sales team for these in writing, along with the export, deletion and renewal answers above:

  • Prices below list. "Is there a volume or committed-use price below the published tiers at my scale?" Google Cloud's page offers a custom quote. SES says it has no contract negotiations, so there the question is which plan fits.
  • SSO beyond the published tiers. If the vendor prices SSO per connection, ask what you pay at your expected connection count, especially past its last published tier. If it prices per user, run your expected SAML share through the script.

Then put the answers into the script's constants and run it again.

When to switch from buying to building

Switch when the case for owning has become durable, not when one month's invoice stings. The signals:

  • The break-even is crossed and staying crossed. Your scale sits above the modelled crossing on your own hour estimate, and growth keeps it there.
  • The vendor blocks the roadmap. A feature customers ask for can't be built on the vendor's model.
  • A compliance requirement no vendor meets. Gate 2 has started to apply.
  • The capability has become core. Fowler's "not a static dichotomy" in practice: it is now part of why customers choose you.

Our workflow automation guide describes the same graduation pattern for internal automations, from an off-the-shelf tool to a rebuilt service.

Run the break-even script yourself

Save the script as break-even.mjs and run node break-even.mjs. It needs Node 18 or later and nothing else: no npm install, no network. Each vendor price is a constant at the top with the page and the read date; each build-side figure is a labelled assumption. Change the hours, the rate, the hosting or the scales to your own, and re-run.

Run metadata: Node v24.20.0, Apple M1 Max, run twice on 2026-10-29 with identical output.

// break-even.mjs: build vs buy for two commodity layers (auth, transactional email), 36 months.
// Node 18+, no dependencies, no network. Run: node break-even.mjs
// Vendor prices were read on the public pricing pages on 2026-10-29. Build-side hours and
// hosting are ASSUMPTIONS (low/mid/high), not Keplaris data. Change any constant and re-run.

const CHECKED = "2026-10-29";
const MONTHS = 36; // horizon; scale is held flat for the whole horizon (no growth curve)

// ---- Buy side: authentication ----
// https://cloud.google.com/identity-platform/pricing (read 2026-10-29)
// "Any account that has signed in within a given month is considered an active user."
// Tier 1 providers (Email, Phone, Anonymous, Social), price per MAU:
// "0 count to 50,000 count $0.00 (Free)", "50,000 count to 100,000 count $0.0055",
// "100,000 count to 1,000,000 count $0.0046", "1,000,000 count to 10,000,000 count $0.0032",
// "10,000,000 count and above $0.0025"
const AUTH_TIER1 = [
  [50_000, 0],
  [100_000, 0.0055],
  [1_000_000, 0.0046],
  [10_000_000, 0.0032],
  [Infinity, 0.0025],
];
// Tier 2 providers (OIDC, SAML): "0 count to 50 count $0.00 (Free)", "50 count and above $0.015"
const AUTH_TIER2 = [
  [50, 0],
  [Infinity, 0.015],
];
// The page's own worked example: 225,000 MAU, "Sub-total: $850". Checked below.

// ---- Buy side: transactional email ----
// https://aws.amazon.com/ses/pricing/ (read 2026-10-29)
// A la carte: "Outbound email $0.10 / 1,000 emails", "$0.12 per GB of attachment data sent"
const SES_A_LA_CARTE_PER_1000 = 0.1;
// Essentials plan, per 1,000 emails: $0.16 up to 10M a month, $0.14 from 10M to 100M, $0.11 above 100M,
// no monthly plan fee. Footnote 2: tiered rates apply marginally, each rate to the emails within its tier.
// Footnote 3: "New SES accounts and account x region combinations with no metered SES activity
// since June 1, 2025 will start on the Essentials plan beginning July 21, 2026."
const SES_ESSENTIALS = [
  [10_000_000, 0.16 / 1000],
  [100_000_000, 0.14 / 1000],
  [Infinity, 0.11 / 1000],
];
const SES_DATA_PER_GB = 0.12;
// SES's first two pricing examples use "Every message is 32KB" and bill 0.000032 GB per message.
const MESSAGE_GB = 0.000032;

// ---- Build side: ASSUMPTIONS, not measured, not from Keplaris projects ----
// Loaded rate: $194,000 a year for one median-wage US developer, from
// https://keplaris.com/blogs/cost-to-build-a-saas-mvp-2026 (BLS median wage grossed up for benefits),
// divided by 2,080 paid hours. Paid hours, not productive hours: this makes building look cheaper.
const LOADED_SALARY = 194_000;
const PAID_HOURS = 2080;
const PRODUCTIVE_HOURS = 1800; // sensitivity row only

// "Build" means assembling on a maintained library or self-hosting open source,
// never hand-written password hashing or crypto.
const AUTH_BUILD_HOURS = { low: 80, mid: 200, high: 400 };   // sign-up, sign-in, sessions, reset, social, MFA, admin
const AUTH_MAINT_HOURS = { low: 4, mid: 10, high: 20 };      // per month: patching, incidents, provider changes
const AUTH_HOSTING_PER_MONTH = 100;                           // assumption: database and compute for the auth service

const EMAIL_BUILD_HOURS = { low: 40, mid: 120, high: 240 };  // self-hosted sending, DNS auth, bounces, complaints
const EMAIL_MAINT_HOURS = { low: 8, mid: 16, high: 30 };     // per month: reputation, blocklists, queue health
const EMAIL_HOSTING_PER_MONTH = 150;                          // assumption: mail servers and IPs, held flat at every volume

const SAML_SHARE = 0.05; // sensitivity row: share of MAU signing in through SAML or OIDC

// ---- helpers ----
const usd = (n) => "$" + Math.round(n).toLocaleString("en-US");
const num = (n) => Math.round(n).toLocaleString("en-US");
const pad = (s, w) => String(s).padStart(w);
const padE = (s, w) => String(s).padEnd(w);
const LEVELS = ["low", "mid", "high"];
const tally = { buy: 0, build: 0 };

function tiered(units, tiers) {
  let cost = 0, floor = 0;
  for (const [ceiling, price] of tiers) {
    if (units <= floor) break;
    cost += (Math.min(units, ceiling) - floor) * price;
    floor = ceiling;
  }
  return cost;
}

const authMonthly = (mau, samlShare = 0) =>
  tiered(mau * (1 - samlShare), AUTH_TIER1) + tiered(mau * samlShare, AUTH_TIER2);
const emailMonthly = (msgs, plan) =>
  (plan === "a la carte" ? (msgs / 1000) * SES_A_LA_CARTE_PER_1000 : tiered(msgs, SES_ESSENTIALS)) +
  msgs * MESSAGE_GB * SES_DATA_PER_GB;

const buildCost = (buildH, maintH, hosting, rate) =>
  (buildH + maintH * MONTHS) * rate + hosting * MONTHS;

// smallest whole-unit scale at which 36 months of vendor cost reaches the build cost
function breakEven(monthlyFn, target, max) {
  if (monthlyFn(max) * MONTHS < target) return null;
  let lo = 0, hi = max;
  while (hi - lo > 1) {
    const mid = Math.floor((lo + hi) / 2);
    if (monthlyFn(mid) * MONTHS >= target) hi = mid; else lo = mid;
  }
  return hi;
}

const RATE = LOADED_SALARY / PAID_HOURS;
const RATE_PRODUCTIVE = LOADED_SALARY / PRODUCTIVE_HOURS;

console.log("break-even (vendor list prices read " + CHECKED + "; build side = stated assumptions, not Keplaris data)");
console.log(`node: ${process.version} | horizon: ${MONTHS} months, scale held flat`);
console.log(`loaded rate: ${usd(LOADED_SALARY)} / ${PAID_HOURS} paid hours = $${RATE.toFixed(2)}/hr`);

const check = authMonthly(225_000);
console.log(`tier check, Identity Platform worked example 225,000 MAU: ${usd(check)}/mo (page says $850) ${check === 850 ? "OK" : "MISMATCH"}`);

// ---- A. Auth ----
const authBuild = {};
for (const l of LEVELS) authBuild[l] = buildCost(AUTH_BUILD_HOURS[l], AUTH_MAINT_HOURS[l], AUTH_HOSTING_PER_MONTH, RATE);

console.log("\n== A. Auth: Identity Platform Tier 1 vs build on a maintained library (36 months)");
console.log(`build + maintenance + hosting: low ${usd(authBuild.low)} | mid ${usd(authBuild.mid)} | high ${usd(authBuild.high)}`);
console.log("       MAU  vendor/mo  vendor 36 mo   cheaper vs low/mid/high build");
for (const mau of [10_000, 50_000, 100_000, 250_000, 500_000, 1_000_000]) {
  const m = authMonthly(mau), t = m * MONTHS;
  const v = LEVELS.map((l) => (t < authBuild[l] ? "buy" : "build"));
  v.forEach((x) => tally[x]++);
  console.log(`${pad(num(mau), 10)}  ${pad(usd(m), 9)}  ${pad(usd(t), 12)}   ${v.join(" / ")}`);
}

console.log("\n-- break-even MAU (36-month vendor cost = 36-month build cost)");
const row = (label, fn, targets) =>
  console.log(padE(label, 44) + LEVELS.map((l) => {
    const be = breakEven(fn, targets[l], 50_000_000);
    return `${l} ${be === null ? "beyond 50M" : num(be)}`;
  }).join(" | "));
row("Tier 1 only, $" + RATE.toFixed(2) + "/hr", (x) => authMonthly(x), authBuild);
row(`${SAML_SHARE * 100}% of MAU on SAML/OIDC, $${RATE.toFixed(2)}/hr`, (x) => authMonthly(x, SAML_SHARE), authBuild);
const authBuild1800 = {};
for (const l of LEVELS) authBuild1800[l] = buildCost(AUTH_BUILD_HOURS[l], AUTH_MAINT_HOURS[l], AUTH_HOSTING_PER_MONTH, RATE_PRODUCTIVE);
row(`Tier 1 only, ${PRODUCTIVE_HOURS} hrs ($${RATE_PRODUCTIVE.toFixed(2)}/hr)`, (x) => authMonthly(x), authBuild1800);
console.log("   (SAML row keeps build hours unchanged; building SAML yourself would add hours, so that row flatters building)");

const aiBuild = buildCost(AUTH_BUILD_HOURS.low, AUTH_MAINT_HOURS.mid, AUTH_HOSTING_PER_MONTH, RATE);
const aiBe = breakEven((x) => authMonthly(x), aiBuild, 50_000_000);
console.log(`\n-- AI-assisted case: low build hours (${AUTH_BUILD_HOURS.low}), mid maintenance (${AUTH_MAINT_HOURS.mid}/mo)`);
console.log(`build cost ${usd(aiBuild)} vs mid ${usd(authBuild.mid)} (${((1 - aiBuild / authBuild.mid) * 100).toFixed(0)}% lower); build hours ${((1 - AUTH_BUILD_HOURS.low / AUTH_BUILD_HOURS.mid) * 100).toFixed(0)}% lower`);
const midBe = breakEven((x) => authMonthly(x), authBuild.mid, 50_000_000);
console.log(`break-even ${num(aiBe)} MAU vs ${num(midBe)} at mid (${((1 - aiBe / midBe) * 100).toFixed(0)}% lower)`);

// ---- B. Email ----
const emailBuild = {};
for (const l of LEVELS) emailBuild[l] = buildCost(EMAIL_BUILD_HOURS[l], EMAIL_MAINT_HOURS[l], EMAIL_HOSTING_PER_MONTH, RATE);

console.log("\n== B. Transactional email: Amazon SES vs self-hosted sending (36 months, 32KB per message)");
console.log(`build + maintenance + hosting: low ${usd(emailBuild.low)} | mid ${usd(emailBuild.mid)} | high ${usd(emailBuild.high)}`);
console.log("   msgs/mo  plan        vendor/mo  vendor 36 mo   cheaper vs low/mid/high build");
for (const msgs of [100_000, 1_000_000, 10_000_000, 50_000_000]) {
  for (const plan of ["a la carte", "essentials"]) {
    const m = emailMonthly(msgs, plan), t = m * MONTHS;
    const v = LEVELS.map((l) => (t < emailBuild[l] ? "buy" : "build"));
    v.forEach((x) => tally[x]++);
    console.log(`${pad(num(msgs), 10)}  ${padE(plan, 10)}  ${pad(usd(m), 9)}  ${pad(usd(t), 12)}   ${v.join(" / ")}`);
  }
}
console.log("\n-- break-even messages per month");
for (const plan of ["a la carte", "essentials"]) {
  row(plan + ", $" + RATE.toFixed(2) + "/hr", (x) => emailMonthly(x, plan), emailBuild);
}
console.log("   (email hosting and maintenance are held flat at every volume; in practice both rise with volume)");

console.log(`\ncells in tables A and B: buy cheaper in ${tally.buy}, build cheaper in ${tally.build}`);

// ---- C. Scenario lines used in the post (illustrative, not clients) ----
console.log("\n== C. Illustrative scenarios (not clients)");
const a = authMonthly(5_000);
console.log(`A  auth at 5,000 MAU: vendor ${usd(a)}/mo, ${usd(a * MONTHS)} over 36 months`);
const B = 800_000;
const b = authMonthly(B), bs = authMonthly(B, SAML_SHARE);
console.log(`B  auth at 800,000 MAU: 50,000 free + 50,000 x $0.0055 = ${usd(50_000 * 0.0055)} + 700,000 x $0.0046 = ${usd(700_000 * 0.0046)}`);
console.log(`   vendor ${usd(b)}/mo, ${usd(b * MONTHS)} over 36 months`);
console.log(`   vs build mid ${usd(authBuild.mid)}: vendor costs ${usd(b * MONTHS - authBuild.mid)} more | vs build high ${usd(authBuild.high)}: ${usd(b * MONTHS - authBuild.high)} more`);
console.log(`   with ${SAML_SHARE * 100}% on SAML: ${num(B * (1 - SAML_SHARE))} Tier 1 = ${usd(tiered(B * (1 - SAML_SHARE), AUTH_TIER1))} + ${num(B * SAML_SHARE)} Tier 2 = ${usd(tiered(B * SAML_SHARE, AUTH_TIER2))}`);
console.log(`   vendor ${usd(bs)}/mo, ${usd(bs * MONTHS)} over 36 months`);
for (const plan of ["a la carte", "essentials"]) {
  const c = emailMonthly(5_000_000, plan);
  console.log(`C  email at 5,000,000/mo, ${plan}: vendor ${usd(c)}/mo, ${usd(c * MONTHS)} over 36 months vs build low ${usd(emailBuild.low)}`);
}

The unedited output of node break-even.mjs from 2026-10-29:

break-even (vendor list prices read 2026-10-29; build side = stated assumptions, not Keplaris data)
node: v24.20.0 | horizon: 36 months, scale held flat
loaded rate: $194,000 / 2080 paid hours = $93.27/hr
tier check, Identity Platform worked example 225,000 MAU: $850/mo (page says $850) OK

== A. Auth: Identity Platform Tier 1 vs build on a maintained library (36 months)
build + maintenance + hosting: low $24,492 | mid $55,831 | high $108,062
       MAU  vendor/mo  vendor 36 mo   cheaper vs low/mid/high build
    10,000         $0            $0   buy / buy / buy
    50,000         $0            $0   buy / buy / buy
   100,000       $275        $9,900   buy / buy / buy
   250,000       $965       $34,740   build / buy / buy
   500,000     $2,115       $76,140   build / build / buy
 1,000,000     $4,415      $158,940   build / build / build

-- break-even MAU (36-month vendor cost = 36-month build cost)
Tier 1 only, $93.27/hr                      low 188,118 | mid 377,360 | high 692,763
5% of MAU on SAML/OIDC, $93.27/hr           low 169,159 | mid 339,181 | high 622,551
Tier 1 only, 1800 hrs ($107.78/hr)          low 207,743 | mid 426,423 | high 790,889
   (SAML row keeps build hours unchanged; building SAML yourself would add hours, so that row flatters building)

-- AI-assisted case: low build hours (80), mid maintenance (10/mo)
build cost $44,638 vs mid $55,831 (20% lower); build hours 60% lower
break-even 309,774 MAU vs 377,360 at mid (18% lower)

== B. Transactional email: Amazon SES vs self-hosted sending (36 months, 32KB per message)
build + maintenance + hosting: low $35,992 | mid $70,315 | high $128,515
   msgs/mo  plan        vendor/mo  vendor 36 mo   cheaper vs low/mid/high build
   100,000  a la carte        $10          $374   buy / buy / buy
   100,000  essentials        $16          $590   buy / buy / buy
 1,000,000  a la carte       $104        $3,738   buy / buy / buy
 1,000,000  essentials       $164        $5,898   buy / buy / buy
10,000,000  a la carte     $1,038       $37,382   build / buy / buy
10,000,000  essentials     $1,638       $58,982   build / buy / buy
50,000,000  a la carte     $5,192      $186,912   build / build / build
50,000,000  essentials     $7,392      $266,112   build / build / build

-- break-even messages per month
a la carte, $93.27/hr                       low 9,628,143 | mid 18,809,757 | high 34,378,581
essentials, $93.27/hr                       low 6,102,212 | mid 12,188,579 | high 23,427,919
   (email hosting and maintenance are held flat at every volume; in practice both rise with volume)

cells in tables A and B: buy cheaper in 28, build cheaper in 14

== C. Illustrative scenarios (not clients)
A  auth at 5,000 MAU: vendor $0/mo, $0 over 36 months
B  auth at 800,000 MAU: 50,000 free + 50,000 x $0.0055 = $275 + 700,000 x $0.0046 = $3,220
   vendor $3,495/mo, $125,820 over 36 months
   vs build mid $55,831: vendor costs $69,989 more | vs build high $108,062: $17,758 more
   with 5% on SAML: 760,000 Tier 1 = $3,311 + 40,000 Tier 2 = $599
   vendor $3,910/mo, $140,769 over 36 months
C  email at 5,000,000/mo, a la carte: vendor $519/mo, $18,691 over 36 months vs build low $35,992
C  email at 5,000,000/mo, essentials: vendor $819/mo, $29,491 over 36 months vs build low $35,992

The output is a snapshot of two vendors' list prices on 2026-10-29 and our stated assumptions, and it leaves out integration, exit, opportunity and risk costs.

How Keplaris approaches build vs buy

Our view, for most early products, is to buy every layer except the core workflow, and to re-run the numbers when a layer's bill or role changes. We sell build work, so weigh this advice accordingly; it is also why the model above is public and its inputs are yours to change. If the scorecard says build for your core workflow, our product design and engineering team can scope it, and tell you which layers to buy around it.

Frequently asked questions

When should you build software instead of buying it?

Build a capability when it is the reason customers pick you, when no vendor meets a hard constraint such as data residency or a compliance rule, or when the vendor's price at your scale has crossed the cost of owning it over 36 months. Buy everything else. Martin Fowler's rule is the short version: for a utility function you buy the package and adjust your process to it, and you build what is strategic.

Is it cheaper to build or buy software?

For commodity layers, buying is usually cheaper until you reach a large scale. Our break-even model, run on public list prices read October 29, 2026, compared Google Cloud Identity Platform and Amazon SES with building each one yourself over 36 months. On our assumptions, auth breaks even at 377,360 monthly active users at the mid estimate (188,118 to 692,763 across our range), and email stays cheaper to buy below 6,102,212 messages a month on all three estimates. These are modelled figures, not measurements.

What is a build vs buy analysis?

A build vs buy analysis compares the full cost and risk of owning a capability against paying a vendor for it, one capability at a time. Price both sides over 36 months: the vendor's price at your scale plus integration and exit costs, against build hours, maintenance hours and hosting. Settle differentiation and hard constraints first, then score time to market, exit cost, fit, team capacity and vendor risk.

What are the pros and cons of building vs buying software?

Building gives you control, an exact fit to your must-haves and no per-user vendor fees at scale, at the cost of build hours, maintenance and on-call time, key-person risk and a slower launch. Buying is faster, starts free or cheap at small scale, and leaves security patching and, for email, deliverability to the vendor. Its costs are repricing and changed default plans, units that differ between vendors, extra charges for enterprise SSO, the vendor's outages and the cost of leaving.

What does build vs buy vs partner mean?

In build vs buy vs partner, the word partner has two meanings. It can mean paying someone else to build the capability for you, which is still building for cost purposes because you own and maintain the result. Or it can mean buying a vendor platform and extending it with your own code, sometimes called buy and extend. The full set of options for a capability is build, buy, buy and extend, or self-host open source.

Does AI-assisted coding change the build vs buy decision?

AI-assisted coding lowers the cost to start building, not the cost to own what you build. In our break-even model, cutting auth build hours from 200 to 80 (a stand-in for an AI-assisted build) while keeping maintenance at 10 hours a month lowers the 36-month build cost by 20% and moves the modelled break-even from 377,360 to 309,774 monthly active users, 18% lower. Maintenance, patching and incident time over 36 months dominate the build side, and AI does not remove them.

How do you avoid vendor lock-in when you buy software?

To avoid vendor lock-in, write down what leaving would cost before you sign. Check the export format and whether it is complete (for auth, whether password hashes and their parameters can be exported), export API rate limits, deletion terms, renewal price caps, notice periods and, for AI vendors, model-training clauses. Keep your own IDs and your own source of truth, so the vendor holds a copy of your data rather than the only one. Add an abstraction layer only where switching is likely.

Next articleShopify Plus vs Shopify Advanced: The Break-Even Math, With Every Fee Sourced

Get in touch.

Whether you have questions or just want to explore what's possible, we're here to help.