Back to Blog
architecturemulti-tenantstripeproductizationsaas

Multi-Tenant SaaS From Client Work: The BYO-Keys Pattern

How I turned a one-off tool for a single trades client into a multi-tenant SaaS using a bring-your-own-API-key pattern. The architectural seam explained.

By Mike Hodgen

Short on time? Read the simplified version

The False Choice That Wastes Money Either Way

Most custom software is throwaway. The moment a client churns, or the moment you want to sell that same tool to someone else, you're starting over. That's the reality most CEOs have lived through at least once, and it's why "build me a custom tool" feels like setting money on fire.

Comparison of three software build approaches: the bespoke trap, the premature-SaaS trap, and building for one user while leaving architectural seams for resale. Three Paths: Bespoke Trap vs Premature SaaS vs Build-for-One-with-Seams

But it doesn't have to be that way. The path from a one-off build to a real multi-tenant SaaS from client work comes down to a handful of architectural decisions you make on day one. Decisions that cost almost nothing at the time and are nearly impossible to retrofit later.

Let me show you what I mean with a real example. A while back I built a job-management tool to win a single trades client, an electrical contractor running his whole operation out of group texts and a spreadsheet. One client. One specific problem. I'll come back to him throughout this article.

The bespoke trap

You commission a tool built for exactly one customer. It works great. Then that customer leaves, or you realize three of their competitors have the same problem and would pay for the same thing. Now you're looking at a rewrite, because the whole thing was wired to one company.

The work was real. The output was good. But it was a dead-end by design, and nobody told you that on day one.

The premature-SaaS trap

The opposite mistake is just as expensive. You decide to build a "platform" first. Six months of engineering, a settings panel for every imaginable customer, an admin dashboard nobody asked for. You're guessing at features for users who don't exist yet.

Then you launch and discover the three things you obsessed over don't matter, and the one thing that does matter, you never built.

Both roads burn cash. The way out is to build for one real user, but leave the seams.

Why I Built for One Real User First

Hypothetical customers lie to you. They answer surveys with what they think they'd do, then behave completely differently when money's on the line. A real owner using your tool daily tells you within a week what matters and what's noise.

With the electrician, I didn't have to guess. He was scheduling jobs, dispatching, and sending invoices through a mess of texts and a spreadsheet that only he understood. I built exactly what replaced that workflow and nothing more.

Real users beat hypothetical ones

The discipline of one user keeps scope brutally tight. Every feature had to earn its place by solving a problem he actually had that week. No "wouldn't it be cool if." No imaginary edge cases.

When you build for one real person, scope creep dies on contact. You ship the thing that gets used, because the person using it is sitting right there telling you what's broken.

Validation is free when the client is paying you to build it

Here's the part most founders miss. I validated a product while getting paid to build it. The client funded the build. The build proved the market. That's a completely different risk profile than spending your own runway guessing.

And because the tooling has changed, this isn't a six-month commitment. A focused build like this ships fast now. (I wrote about the new timeline for custom software if you want the speed angle.)

But there's a trap hiding in here. If you ONLY build for that one owner, you've built a dead-end again. Validated, useful, and impossible to resell. That's where the seams come in.

The One Decision That Turns a Build Into a Product

This is the heart of it. The single decision that turned a bespoke tool into the seed of a product was how I handled payments.

The instinct is to centralize. Wire up one Stripe account, route everyone's money through it, manage billing centrally. That's how you end up eating processing fees, managing a payments operation you never wanted, and rewriting billing logic for every new customer.

I did the opposite. I left the payment keys empty by default and let each owner bring their own.

Read the tenant's key first, fall back to env, fall back to pay-by-check

In production, STRIPE_SECRET_KEY stays empty. The code never assumes there's one global payment account. Instead, when it needs to invoice, it walks a fallback chain:

Flowchart showing the BYO-keys payment fallback chain: read the tenant's own Stripe key first, fall back to environment variable, then fall back to pay-by-check invoicing. BYO-Keys Payment Fallback Chain

  1. Read the tenant's own pasted key first. Each owner has a settings screen where they paste their own Stripe secret key into their tenant record. If it's there, the invoice goes through their account and their money lands in their bank.
  2. Fall back to the environment variable if one exists. Useful for testing or a single-account setup, but empty in production by design.
  3. Fall back to pay-by-check if there's no key at all. No Stripe account? The invoice still generates, marked pay-by-check. The tool works on day one without anyone configuring anything.

That third fallback is why the electrician was productive immediately. He didn't have a Stripe account yet, didn't matter. The tool sent invoices marked pay-by-check, he collected, and the build delivered value on day one.

Leave the payment keys empty by default

Now look at what this bought me. The hundredth client self-onboards by pasting their own key into settings. No code change. No deploy. No per-customer billing branch to maintain.

Each owner's money flows to their own account. I never touch it, never eat the processing fees, never become a payments company by accident. This is the bring-your-own-keys pattern, and I've written the deeper technical version there.

One small decision, made the first day, on the very first client. It cost me maybe an hour of extra thought. It's the difference between a tool that serves one electrician and a product that serves a thousand contractors who each run their own books.

That's the whole game. Build for one, but write the code so the second, tenth, and hundredth slot in without you rewriting anything.

The Other Seams: Per-Tenant Credentials and Isolated Data

The payment key isn't special. It's just the first instance of a pattern you apply everywhere a customer has something that belongs to them and not to your codebase.

Credentials live with the tenant, not the codebase

Any per-customer secret follows the same rule. Payment keys, email-sending credentials, SMS provider tokens, third-party API integrations. None of it goes in a global environment variable. All of it lives in the tenant record.

The electrician sends invoices from his email, not mine. He texts job reminders from his number, not a shared one. Every credential that's "his" lives with his tenant. When the second client shows up, they paste in their own, and the system routes their traffic through their accounts automatically.

If I'd hardcoded one email provider and one SMS account into env vars, every new customer would mean either sharing my accounts (a compliance and deliverability nightmare) or rewriting the integration layer. Instead, the credential lookup is identical to the payment lookup: read the tenant's value first, fall back gracefully if it's missing.

Data isolation from row one

The other seam is data. From the very first table I created, every row carried a tenant_id, even when there was exactly one tenant in the entire system.

Multi-tenant architecture diagram showing one shared codebase serving three isolated tenants, each with their own Stripe key, email and SMS credentials, and tenant-scoped data. Multi-Tenant Architecture with Per-Tenant Credentials and Data Isolation

This feels pointless when you have one customer. It is not pointless. Adding a tenant_id column when you have one customer costs nothing, a single column on a few tables. Retrofitting tenant isolation across 50 tables when you already have a hundred customers in production is a migration nightmare that can take weeks and risks leaking one customer's data into another's view.

Every query scopes to the tenant. Every read, every write, filtered by tenant ID from row one. I covered the full reasoning in every client gets their own isolated data, but the short version is this: isolation is free if you build it in and brutally expensive if you bolt it on.

The principle ties all the seams together. Build for one. Leave the joints where the next customer connects without a rewrite.

What This Costs You on Day One (Honest Accounting)

I'm not going to pretend the seams are free. They're not.

The overhead is real but small

Adding the seams costs maybe 10 to 15 percent on top of the initial build. You need a settings screen where owners paste their keys. You need a tenant table. You need to scope every query. You need the fallback logic for payments and credentials.

Bar chart comparing the small day-one cost of adding multi-tenant seams (10 to 15 percent) versus the weeks-long expensive retrofit of bolting on tenant isolation later. Day-One Seams: Cheap Now vs Expensive Retrofit

That's real work. On a build that would otherwise ship in a week, you're adding a day, maybe a bit more. It's not nothing, and I'd be lying if I told you it was.

When NOT to do this

If you are genuinely, truly certain this is a one-off internal tool that will never be resold and never serve a second customer, skip it. An internal dashboard for your own ops team doesn't need a tenant table. Don't build seams you'll never use.

But be honest about that certainty. In trades, professional services, local business, the client's competitor has the exact same problem. Always. If there's any real chance the second customer exists, the 15 percent buys you a repeatable product instead of a dead-end. That's one of the best returns you'll find in software.

And I'll be straight about what does NOT carry over cleanly. Branding, onboarding flow, and customer support still need work per customer. The architecture is reusable. The go-to-market is not. The seams give you a product engine, not a finished business. You still have to build the part that sells it.

From One Client to a Hundred Without a Rewrite

Here's where it pays off. When the second trades client showed up, onboarding them was almost free.

The second customer is almost free

No fork of the codebase. No per-customer branch to maintain. No "let me copy the project and swap out the config" afternoon that turns into a maintenance liability you'll regret for years.

The second client got their own tenant record. They pasted in their own keys. Their data scoped to their tenant ID automatically, because it always had. The marginal engineering cost of customer number two was near zero, because all the work that would have made it expensive was already done on day one for customer number one.

Self-onboarding is the unlock

The real shift is when customers onboard themselves. Once the seams exist, a new owner signs up, pastes their keys, and starts working without me touching the code at all. That's the moment a bespoke build becomes a paid product you can scale.

Infographic showing the progression from one custom-built client to a hundred self-onboarding tenants with near-zero marginal cost, all running on a single codebase. From One Client to a Hundred, The Self-Onboarding Unlock

The path from single-tenant to multi-tenant SaaS wasn't a rewrite. It was turning on the seams I'd already built. One codebase, near-zero marginal cost per new tenant, each customer running on their own keys and their own isolated data.

That's the answer to the concern I opened with. Custom work is only throwaway if you architect it to be. Done right, the bespoke build that won you one client is the seed of a product that serves a hundred.

Build It Once, Own It Forever

Here's the lesson if you're a CEO commissioning custom software. Ask one question before anyone writes a line of code: is this being built as a dead-end, or with the seams that let it become an asset?

Because the difference is almost free to add on day one and impossible to retrofit later. A tool built for one customer can either die when that customer leaves, or become something you reuse, resell, and scale. Same build effort, give or take 15 percent. Wildly different outcomes.

This is the thinking I bring to every project. I'm not just shipping you a tool that solves today's problem. I'm building the seam for what comes next, so the money you spend on a build today becomes an asset you own forever instead of a cost you write off.

If you've been burned by custom work that turned into a dead-end, or you're about to commission something and want it built right, let's talk about your build.

Ready to bring AI leadership into your company?

I work with a small number of companies at a time. If you're serious about AI, apply to work together and I'll review your application personally.

Apply to Work Together

Get AI insights for business leaders

Practical AI strategy from someone who built the systems — not just studied them. No spam, no fluff.

Ready to automate your growth?

Book a free 30-minute strategy call with Hodgen.AI.

Book a Strategy Call