Skip to main content
Migrate Already selling? Move your customers to Keylight without re-issuing a single key.
Keylight
Blog
licensing scaling architecture

Why Software Licensing Gets Hard When Apps Scale

4 min read Nicolas Demanez — Founder

The first version of licensing in almost every app is twenty lines of code. A key is checked, a boolean is set, paid features turn on. It works perfectly — for a while. Then the app grows, and that twenty lines quietly becomes one of the most fragile parts of the product. This post is about why that happens, and how to see it coming.

The check that worked at launch

When you have fifty customers, a naive license check is genuinely fine. You hardcode a validation rule, or you call a small endpoint that looks the key up in a table. A bad key fails, a good key passes. You ship.

It works because at fifty customers, the edge cases have not happened yet. Nobody has asked for a refund. Nobody has a second Mac. Nobody has emailed you from a plane. You have one plan, so there is nothing to differentiate. The naive check is not wrong — it is just untested by reality.

Scale is the process of every one of those untested cases happening, repeatedly, at once.

Where it starts to break

Here is the order it usually breaks in.

Refunds. Your fifth refund makes you realise a paid-for key is still working in the wild because nothing ever revokes it. You start revoking by hand. By the fiftieth refund, you have forgotten a few, and you have paid-feature keys out there that were never paid for.

Multiple devices. Customers get new laptops. Without device tracking, one key works everywhere forever — so a key shared in a forum supplies a hundred installs. Add a device limit and you immediately need deactivation, or honest customers get locked out of hardware they replaced.

More than one plan. The moment you add a “pro” tier, the license has to carry what was bought, not just that something was bought. A boolean cannot express that. Now your license needs structure.

Offline customers. Your support inbox starts getting “the app won’t open and I have no wifi.” Your check needed the network, and a meaningful slice of desktop usage does not have it.

None of these is hard alone. The problem is they arrive together, as support tickets, while you are trying to build the actual product.

The single point of failure nobody designed

There is a deeper, quieter failure that scale exposes: the license server becomes a launch-time dependency for every customer at once.

While you had fifty customers, your validation endpoint was never under load and never noticed. At five thousand, a slow deploy, a database hiccup, or a brief outage means thousands of apps trying to validate and failing simultaneously. A component that was invisible becomes the thing that takes your whole user base down.

This is an architecture problem, and it has an architecture answer: do not make the server a launch-time dependency. Use offline license validation — a signed license the app verifies locally — so the app launches with no server call, and the server is consulted only occasionally, in the background. An outage then affects nobody’s launch. The licensing server stops being a single point of failure because the critical path never touches it.

Designing for scale from the start

You do not need to over-build on day one, but you should pick a model that has room for the edge cases instead of one that excludes them.

A license that scales is a signed entitlement: a structured document — product, plan, device limit, expiry, revoked flag — verified locally and signed so it cannot be forged. That single design absorbs almost everything above. Plans are just fields. Refunds flip the revoked flag. Device limits are a number the activation system counts against. Offline use is free because verification is local.

await licensing.checkOnLaunch()

switch licensing.state {
case .licensed:     enablePaidFeatures()
case .trial(let d): showTrialBanner(daysLeft: d)
case .expired:      showRenewalPrompt()
case .invalid:      showActivationSheet()
}

The honest question is build versus buy. The cryptography is not the expensive part — the operational surface is: webhook handlers for refunds and chargebacks, a revocation pipeline, device-activation tracking, a customer portal so device swaps do not become tickets. That surface is what costs real engineering time to maintain forever, and it is why many teams reach for a dedicated licensing layer once the edge cases start arriving.

This is the gap Keylight is built for. It is a licensing layer designed for scale from the first customer: Ed25519-signed leases the app verifies offline, so the server is never on the launch path; automatic revocation on refunds and chargebacks; device-activation tracking; and a customer portal so device swaps never become tickets. The whole operational surface is handled, and it behaves the same whether you have fifty customers or fifty thousand — the naive check breaks somewhere in between, and a layer built for scale does not.

The lesson is not “your launch-day check was wrong.” It is that licensing is one of the things that gets harder as the app gets more successful, not easier — so it is worth choosing a model that grows with you. If you have hit a scaling wall we should write about, send us your feedback.

Frequently asked

Why does a simple license check stop working as an app grows?+

A naive check ignores refunds, device limits, multiple plans, and offline use. Each edge case it skips becomes a support ticket or a revenue leak once you have thousands of customers instead of dozens.

What is the most common licensing mistake at scale?+

Treating the license server as a launch-time dependency. When it slows or fails, every customer is affected at once — a single point of failure that was invisible while traffic was low.

Should I build licensing myself or use a layer?+

Building it is fine at small scale. The operational surface — webhooks, revocation, device tracking, a customer portal — is what becomes expensive to maintain, which is where a dedicated layer pays off.

Ready to ship?

Create your account and start licensing your apps in under a minute. Free forever tier included.

Start Free