Morteza Taghdisi

Writing10 min read
Abstract technical illustration representing an SDK as a boundary living inside another team's application
Architecture & Platform ThinkingMay 28, 2026

SDK Architecture For Systems Other Developers Depend On


An SDK looks small from the outside.

A package. A few public methods. Some documentation. Maybe a sample app.

That surface can make the architecture feel smaller than it is. But an SDK is not just code shipped to another application. It is a boundary between your platform and someone else's product.

That boundary has consequences.

Once teams integrate your SDK, your decisions enter their build system, their startup path, their crash reports, their release process, their support tickets, and their user experience.

That is why SDK design is architecture.

Not because every SDK needs a complicated internal system. The opposite is usually true. SDK architecture matters because a small public surface can create a large operational and product commitment.

The SDK Is A System Boundary

An API boundary usually sits between two services.

An SDK boundary sits inside another team's application.

That changes the architecture problem.

When a backend service changes, the owning team can usually deploy a fix. When an SDK has a bad public API, unclear initialization model, heavy dependency, or broken compatibility promise, the fix depends on every host application upgrading.

That may take days. It may take months. Some customers may never upgrade.

This is why SDK architecture has to be designed around the caller's reality, not only the SDK team's internal design.

The architect question is not:

"How do we package this feature?"

The architect question is:

"What boundary are we asking other developers to build their application around?"

That question changes the design.

The Public Surface Becomes The Product

The public API is not a wrapper around the real product.

For the developer integrating the SDK, the public API is the product.

If the public surface is confusing, the product feels confusing. If errors are unclear, the product feels unreliable. If initialization is fragile, the product feels risky. If versioning is careless, the product feels expensive to adopt.

The warning sign is an SDK that asks the caller to assemble internal modules before doing anything useful.

kotlin
// Leaky boundary: the caller assembles internal SDK concepts
PaymentsSDK.initialize(
    PaymentsModule(
        auth = AuthModule(clientId),
        analytics = AnalyticsModule()
    )
)

A better public surface starts from the caller's mental model:

kotlin
PaymentsSDK.initialize(context) {
    apiKey = BuildConfig.PAYMENTS_API_KEY
    environment = Environment.PRODUCTION
}

The internal modules may still exist. The caller does not need to assemble them.

The architecture decision is simple but important: internal structure should not leak into the public contract unless the caller genuinely needs that control.

Compatibility Is A Product Promise

SDK compatibility is harder than backend compatibility because the SDK runs in environments you do not control.

Different customers will use different versions. Mobile apps may stay in the wild for months. Enterprise customers may pin dependencies. Some teams may upgrade only during scheduled release windows.

That means every public type, method, enum, callback, configuration key, and error category becomes part of a compatibility promise.

Even a cleaner product model can be a breaking change if integrators have built logic around the old one. Host apps may have exhaustive state handling. Analytics may depend on old result names. Support documentation may describe old failure behavior. Tests may assert old states.

The architect has to ask:

  • is this a breaking change?
  • can we add the new model without removing the old one immediately?
  • how long do we support both?
  • how will integrators discover the change?
  • what happens if old and new SDK versions talk to the same backend?
  • what telemetry tells us which versions are still active?

Compatibility is not just semantic versioning. It is the operational plan for helping other teams move safely.

The general mobile/backend compatibility window belongs in the next article. This article's narrower point is that once an SDK type ships, it becomes someone else's source code dependency.

SDK Architecture Extends Into The Backend

SDK design cannot be separated from backend design.

A mobile SDK may expose one clean method:

kotlin
PaymentsSDK.startCheckout(cartId)

Behind that call, the system may need:

  • session creation
  • authentication
  • payment intent creation
  • fraud checks
  • retry handling
  • receipt generation
  • status polling or push updates

The SDK does not own all of that behavior. But it shapes how the host app experiences it.

If the backend returns unstable internal states, the SDK must either leak them or translate them. If the backend changes response shapes too quickly, the SDK becomes a compatibility buffer. If the backend lacks idempotency, the SDK cannot make retries safe by itself.

This is where SDK architecture becomes system architecture.

The SDK is not only a client library. It is part of a product workflow that crosses device, network, backend, and support boundaries.

The architect has to decide where responsibility lives:

  • which state belongs in the backend?
  • which behavior belongs in the SDK?
  • which errors should the host app handle?
  • which retries are safe inside the SDK?
  • which operations need server-side idempotency?
  • which events must be visible to platform teams?

If those decisions are unclear, the SDK becomes a place where backend uncertainty is hidden until customers feel it.

Dependency Weight Is An Architecture Decision

SDK dependencies are not internal details.

Every dependency you add enters the host application's build, dependency graph, binary size, startup cost, security review, and conflict surface.

Adding a networking library may be convenient for the SDK team. It may conflict with the host app's dependency policy. Adding a large analytics dependency may help observability. It may increase app size in a way the host team cannot accept. Adding a transitive dependency may create version conflicts that integrators have to debug.

The SDK team pays the cost once.

Every integrator pays it repeatedly.

That asymmetry matters.

Before adding a dependency, ask:

  • is this dependency visible to the host app?
  • can it conflict with common app dependencies?
  • does it affect startup time?
  • does it affect binary size?
  • does it introduce security review work?
  • can we isolate it?
  • can we make it optional?
  • can the same behavior be provided by the host app?

This is not about avoiding dependencies at all costs. It is about treating dependency weight as part of the public architecture.

Observability Has To Cross The Boundary

SDK failures are hard to debug because the failure often crosses ownership lines.

The host app sees a failed checkout. The SDK sees a timeout. The backend sees a partial request. The platform team sees no clear correlation. Support sees a customer complaint.

If the SDK does not provide useful signals, every team gets a fragment of the truth.

Good SDK architecture starts with a few stable diagnostic signals:

  • stable error codes
  • correlation IDs
  • SDK version
  • safe lifecycle callbacks for important events

This does not mean the SDK should dump logs into the host app or expose sensitive internals.

It means failures should be diagnosable without asking every integrator to become an SDK engineer.

The user-facing copy may still belong to the host app. The diagnostic contract belongs to the SDK.

The next article treats client observability as a full mobile/backend system concern. Here, the SDK-specific decision is whether integrators receive stable diagnostic signals or only vague failure callbacks.

Release Windows Are Part Of The Design

Backend teams often think in deployment windows.

SDK teams have to think in adoption windows.

Shipping a new SDK version does not mean the ecosystem moved. It means the option to move exists.

Some customers will upgrade quickly. Some will wait. Some will skip versions. Some mobile users will keep old app versions long after the SDK team considers them outdated.

That reality changes backend rollout.

If a backend endpoint stops supporting SDK version 2.x too early, host apps break. If a new SDK requires a backend capability that is not globally deployed yet, customers hit inconsistent behavior. If deprecation notices are unclear, integrators discover breaking changes during their own release crunch.

An SDK architecture plan should include:

  • supported version windows
  • backend compatibility windows
  • deprecation policy
  • migration guides
  • telemetry for active SDK versions
  • feature flags or capability negotiation where needed
  • a clear policy for security fixes

This is not paperwork. It is how a platform keeps trust.

The broader mobile release-window problem belongs in the next article. For SDK architecture, the key commitment is the support window for the public contract you shipped.

The Support Burden Is Designed Early

Every unclear SDK decision becomes a support cost.

If initialization order is unclear, support gets setup questions.

If errors are unclear, support gets debugging questions.

If versioning is unclear, support gets upgrade questions.

If backend behavior is unclear, support gets incident questions.

The support burden is not separate from architecture. It is often the first place architecture mistakes become visible.

When designing an SDK, ask:

  • what will developers misunderstand first?
  • what will they do wrong in a blank app?
  • what error will they see when that happens?
  • can support diagnose the issue without private context?
  • can the SDK guide the developer toward the fix?
  • does the documentation match the actual public API?

The best SDK architecture reduces support load by making the correct path obvious and the incorrect path diagnosable.

What Belongs In The Trunk And What Belongs In The Branch

This article is about SDK architecture at the system level.

It should help you reason about:

  • SDKs as system boundaries
  • compatibility as a product promise
  • dependency weight as a platform cost
  • backend and SDK responsibility splits
  • observability across ownership lines
  • release windows and support burden

The deeper mechanics belong in the Mobile SDK Design branch. The trunk gives the system decision frame. The branch gives the implementation depth.

A Practical SDK Architecture Checklist

Before shipping or redesigning an SDK, ask:

  1. What product boundary does this SDK expose?
  2. Which internal concepts are leaking into the public API?
  3. What public types or methods are now compatibility commitments?
  4. How long will old SDK versions remain supported?
  5. Can old SDK versions and new backend behavior coexist?
  6. What dependencies does the SDK add to host applications?
  7. Which failures should the SDK handle internally?
  8. Which failures should the host application handle?
  9. What information is needed to debug failures across SDK and backend?
  10. Can support diagnose common integration mistakes from errors and telemetry?
  11. What is the upgrade path for breaking changes?
  12. What will become harder for integrators after this design?

These questions do not make the SDK perfect.

They make the platform commitment visible before other teams depend on it.

Where To Go Deeper

The Mobile SDK Design series goes deeper into SDK implementation mechanics: public API surface, initialization state, error models, distribution, secure defaults, and cross-platform consistency.

Use that branch when you need the mechanics. Use this article when you need the architecture decision frame.

Summary

An SDK is a small package with a large boundary.

It lives inside someone else's application, moves at someone else's release pace, and turns your platform decisions into their integration experience.

That is why SDK architecture is not just packaging. It is contract design, compatibility planning, dependency control, observability, release strategy, and support design.

The architect's job is to make those commitments explicit before they become expensive for every developer who depends on the SDK.