TL;DR
"We support both" is the most expensive sentence in SaaS architecture. Every "both" doubles your surface area: testing, documentation, operational runbooks, security audits, and the mental model your team carries. In SaaS codebases where "we support both MySQL and PostgreSQL" or "we support both AWS and GCP" becomes the norm, that duplication becomes a large and quiet share of engineering overhead. The cost isn't visible in sprint planning because it's distributed: an extra 30 minutes on every PR review checking both paths, an extra 2 hours on every deployment verifying both configurations, an extra week on every security audit. The fix isn't always eliminating one option... sometimes you genuinely need both. The fix is making the decision consciously, quantifying the tax, and choosing "both" only when the business value exceeds the ongoing engineering cost.
Part of the SaaS Architecture Decision Framework ... a comprehensive guide to architecture decisions from MVP to scale.
Where "Both" Comes From
The decision to support both is never made at an architecture meeting. It accumulates.
The customer-driven "both": Your biggest prospect uses MongoDB. Your application runs on PostgreSQL. Sales says "can we support both?" Engineering says "it's just a database adapter." Six months later, the adapter has 47 special cases for MongoDB's different join behavior, transaction semantics, and query syntax.
The acquisition "both": Two companies merge. One runs on AWS, the other on GCP. "We'll support both while we migrate." Three years later, both are still supported. The migration never happened because there was always a more urgent feature.
The team preference "both": Half the team prefers REST, half prefers GraphQL. "Let's support both." Now every API endpoint has two implementations, two sets of documentation, and two integration test suites.
The backward compatibility "both": You shipped API v1. Now v2 is better. "We'll support both until customers migrate." V1 is still running five years later with 12% of traffic and 40% of the API-related bugs.
The Hidden Costs
The cost of "both" lands in four places: testing, operations, cognitive load, and security.
Testing Overhead
Each supported configuration multiplies the test matrix, and adding a second cloud provider multiplies it again. The multiplier isn't exactly 2x because some tests are configuration-independent. But the configuration-specific tests... the ones that verify behavior unique to each option... are where the bugs hide. And those bugs are the hardest to reproduce because your development environment runs one configuration while production might run the other.
Operational Overhead
Every runbook, every monitoring dashboard, every alert configuration needs to work for both. The on-call engineer at 3 AM needs to know not just "the database is slow" but "the MySQL database is slow and the fix is different than the PostgreSQL fix."
Concretely: PostgreSQL query analysis runs through pg_stat_statements, MySQL through performance_schema. The monitoring dashboards differ. The optimization runbooks differ. The on-call engineer needs to know both.
Expect incidents in the less-used configuration to take longer to resolve, because engineers have less operational muscle memory for it.
Cognitive Load
Every engineer who touches the codebase needs to understand both configurations. Not just "they exist" but "how they differ and when the difference matters."
// The abstraction that doesn't fully abstract
async function getUser(id: string): Promise<User> {
if (config.database === "postgresql") {
// PostgreSQL: JSONB query for preferences
return db.query(`SELECT *, preferences->>'theme' as theme FROM users WHERE id = $1`, [id]);
} else {
// MongoDB: dot notation for nested fields
return db
.collection("users")
.findOne({ _id: new ObjectId(id) }, { projection: { "preferences.theme": 1 } });
}
}
This pattern... a function that branches on configuration... appears innocuous. But multiply it by 200 database operations and you have a codebase where every function has two code paths that diverge in subtle ways.
Security Surface Area
Every "both" doubles your security audit scope. Two databases means two sets of access controls, two sets of encryption configurations, two sets of vulnerability scanning pipelines.
Here is how that fails: the PostgreSQL deployment enforces tenant isolation with Row-Level Security, while the MongoDB deployment relies on application-level filtering. A bug in the application filter exposes cross-tenant data... but only in the MongoDB configuration. If security testing focuses on the PostgreSQL path, that bug can survive for months.
The Decision Framework
Before accepting "we support both," quantify the cost:
Step 1: Calculate the Ongoing Tax
| Cost Category | Estimation Method |
|---|---|
| Testing | Count configuration-specific tests. Multiply by average test maintenance time. |
| CI/CD | Number of additional build/deploy pipelines. Multiply by compute cost and maintenance time. |
| Documentation | Pages of configuration-specific documentation. Multiply by update frequency. |
| On-call | Additional runbooks and dashboards. Multiply by incident frequency in each configuration. |
| Security | Additional attack surface. Multiply by audit frequency and remediation time. |
| Cognitive load | Number of engineers who need to understand both. Multiply by ramp-up time. |
Step 2: Calculate the Business Value
| Value Source | Estimation Method |
|---|---|
| Revenue at risk | ARR from customers who require the second option |
| Market expansion | TAM unlocked by supporting the second option |
| Competitive advantage | Does "both" differentiate from competitors? |
| Acquisition requirement | Is "both" a requirement for an M&A deal? |
Step 3: Compare Honestly
If the annual engineering tax of "both" exceeds the annual revenue benefit, cut one. This sounds obvious, but the trap is common: supporting MySQL for a single customer whose revenue is a fraction of the engineering overhead it takes to maintain.
When "Both" Is Justified
I'm not arguing that you should never support multiple configurations. Some cases genuinely warrant it:
Multi-cloud for enterprise customers. If your enterprise tier sells to companies with cloud mandates (government, regulated industries), supporting AWS and GCP is a revenue driver. Budget the tax explicitly.
Database-per-tenant for isolation. If your security model requires per-tenant database instances and customers bring their own database, supporting PostgreSQL and MySQL is a product feature.
API versioning during migration. Supporting v1 and v2 during a 6-month migration window is pragmatic. Supporting v1 and v2 indefinitely is a tax.
The key: in each justified case, the "both" has a clear business reason, a defined scope, and ideally an expiration date.
The Exit Strategy
When you decide to eliminate one option, the migration path determines whether it takes 3 months or 3 years.
The Strangler Fig for "Both"
- Stop new development on the deprecated option. All new features only need to work with the chosen option.
- Migrate existing customers. Provide migration tooling and a timeline. Offer migration support as a service.
- Set a sunset date. Announce it 6-12 months in advance. Stick to it.
- Remove the code. After the sunset date, delete the abstraction layer and all configuration-specific code. The code reduction alone improves velocity.
The Conversation with Customers
"We're consolidating from two database backends to one. This lets us ship features 30% faster and reduce our security surface area. We'll provide full migration support and a 9-month transition period."
Frame it as a quality and velocity improvement, and plan for three kinds of pushback: customers who will migrate once the deadline is real, customers with genuine compliance, contractual, or reliability constraints (build the migration plan with them), and customers who are truly locked in (negotiate a custom support contract).
Common "Both" Scenarios and Recommendations
| "Both" Scenario | Recommendation | Reasoning |
|---|---|---|
| MySQL and PostgreSQL | Pick PostgreSQL | JSONB, RLS, better extension ecosystem for SaaS |
| PostgreSQL and MongoDB | Pick one based on workload | MongoDB excels at document-heavy workloads; PostgreSQL covers relational + JSONB. Supporting both is rarely worth the adapter complexity. |
| REST and GraphQL | Pick one based on clients | Mobile-heavy = GraphQL; B2B integrations = REST |
| AWS and GCP | Pick one unless enterprise requires it | Multi-cloud tax is 30-50% of infrastructure engineering time |
| Docker and bare metal | Docker | The abstraction cost is negligible; operational benefits are real |
| API v1 and v2 | Sunset v1 within 12 months | Every additional API version is permanent maintenance |
| Webpack and Vite | Vite | The migration is a one-time cost; the build speed improvement is permanent |
| Jest and Vitest | Pick one | They're similar enough that maintaining both is pure overhead |
When to Apply This
- Your team mentions "we support both" for any infrastructure component
- CI/CD pipelines run multiple configurations and you're not sure why
- Bug reports include "only happens when configured with X"
- New engineers take extra time ramping up because of configuration complexity
When NOT to Apply This
- You genuinely serve customers on different platforms and the revenue justifies the tax
- The "both" is temporary with a defined sunset date
- The abstraction layer is clean and the configurations are truly interchangeable
Paying the hidden tax of "we support both"? I help teams quantify the cost, make the decision, and execute the migration.
Continue Reading
This post is part of the SaaS Architecture Decision Framework ... covering database design, deployment strategy, API patterns, and infrastructure decisions.
More in This Series
- Boring Technology Wins ... Why choosing one mature option beats supporting both
- Build vs Buy: The SaaS Engineering Decision ... When to build custom vs adopt existing solutions
- Tech Stack as Capital Allocation ... Every "both" is a capital allocation decision
Related Guides
- SaaS Billing Architecture with Stripe ... One area where "both" is never worth it
