Most SDK teams do not consciously choose a delivery model. They inherit one.
The first release of a new platform ships as a single archive because that’s the fastest way to get something into customers’ hands. The next few releases follow the same pattern because it works. By the time the team has five product variants, three middleware stacks, and a growing ecosystem of customer-contributed drivers, the packaging model has quietly become the bottleneck — and migrating off it requires rebuilding tooling, retraining customers, and renegotiating release cadences across the organisation.
The packaging decision deserves more attention than it usually gets, because it is one of the few SDK architecture choices that is genuinely hard to reverse. The C API can be versioned. The HAL can be refactored. The build system can be modernised in stages. The model by which you deliver components to customers, however, sets the shape of every release process, every CI pipeline, every customer onboarding flow, and every community contribution path you will ever have. Three dominant models exist in the embedded SDK landscape today, and each represents a point on a clear simplicity-to-scalability spectrum.
Three models, one spectrum
The monolithic package is the simplest: a single versioned archive containing every component relevant for a given supported product, including CMSIS headers, HAL and LL drivers, middleware, the BSP, examples, and documentation. One archive per product series. One version number. One release event.
The meta-tool model is a step further: a manifest file, commonly YAML-based, describes a graph of Git repositories pinned to specific revisions. A meta-tool checks out and manages these repositories on the developer’s machine. The SDK is no longer a single archive but an orchestrated set of component repositories.
The component registry model is the most scalable: individual middleware components are published to a central package index with semantic versioning, component manifests declare inter-component dependencies, and the build system resolves and downloads the dependency graph automatically. The SDK becomes a curated index of independently versioned components rather than a single deliverable.
These are not interchangeable. Each model carries trade-offs that compound over time, and choosing the right one depends on ecosystem size, team structure, and where the SDK is in its lifecycle.

The monolithic package
The monolithic package is simple to bootstrap and easy to communicate. A customer downloads one file. They unpack it. They have everything they need. There is no meta-tool to install, no manifest to understand, no registry to authenticate against. For a narrow, stable product family with a small engineering team and a small customer base, this is genuinely the right answer — and treating it as anything more sophisticated is over-engineering.
The model breaks down on five specific axes as the platform grows.
First, one package per product series tends to produce multiple near-identical archives with no shared update mechanism. A bug fix in a HAL driver shared across three product families requires three separate releases, and the divergence between those archives accumulates because each release picks up unrelated changes from the others.
Second, dependency management between solutions becomes manual. There is no tooling to resolve compatibility between an application built on one archive and a middleware component pulled from another. Customers end up building their own internal compatibility matrices, which is a problem the SDK team should be solving on their behalf.
Third, releases are infrequent and high-risk because everything ships together. A small fix in one driver requires re-testing the entire archive across every supported target. The result is either long release cycles or insufficient testing, and usually both.
Fourth, there is no easy path for community contributions. A third-party driver author has no place to publish independently. Every contribution must be merged into the central archive, reviewed against everything else in it, and timed to a full SDK release.
Fifth, consumers absorb the entire package even for small fixes. A customer who needs a single driver patch downloads the full SDK, rebuilds against it, and re-validates their application — a tax the customer pays for the simplicity the SDK team chose.
The monolithic package is best treated as a starting point, not a long-term architecture. Teams that are still on it after five years of platform growth are usually paying compounding maintenance cost without realising it.
The meta-tool model
The meta-tool model addresses most of the monolithic model’s failure modes by decomposing the SDK into a graph of independently versioned Git repositories, orchestrated through a manifest. A typical workspace manifest looks something like this:
manifest:
defaults:
remote: primary
remotes:
– name: primary
url-base: https://github.com/example-vendor
– name: community
url-base: https://github.com/community-org
projects:
– name: sdk-core
remote: primary
revision: v3.2.1
– name: open-rtos
remote: community
revision: v3.7.0
path: rtos/open-rtos
What this enables is fine-grained component versioning, independent release cycles for individual repositories, community contribution to specific submodules without a central archive merge, and reproducible builds across teams. Yocto for Linux-capable SoCs is a long-standing instance of this model, and the embedded MCU world has converged on similar patterns over the past several years.
The cost is real, and it shows up in five recurring places.
The learning curve is steep, and on complex projects the initial setup can take days rather than hours. New customers evaluating the SDK encounter an extra layer of tooling before they reach a running firmware image, which directly conflicts with the thirty-minute getting-started target that drives evaluation outcomes.
The meta-tool itself becomes a hidden infrastructure dependency. Every developer machine, every CI runner, every customer build environment has to have it installed and configured. When the meta-tool changes, every consumer has to keep up.
Upstream repository deletions or renames can break the entire workspace. A community-hosted submodule that gets archived, force-pushed, or moved to a new organisation can break customer builds without warning. SDK teams have to mirror upstream repositories to insulate against this, which is itself an infrastructure commitment.
SHA pinning is reproducible but opaque. A manifest that pins to commit abc123def produces a deterministic build, but the developer reading it has lost the version context — they don’t know whether abc123def is a tagged release, a development snapshot, or a hot-fix branch. Tag-based pinning helps, but only if the upstream is disciplined about tagging.
Cross-cutting changes are hard to coordinate. A change that touches five repositories — say, a new error code propagated through the HAL, OSAL, BLE stack, sample applications, and documentation — requires coordinated pull requests across all five, with no atomic merge primitive. SDK teams develop tooling around this, but it is a permanent maintenance line item.
The meta-tool model is the architecturally preferred middle ground for SDKs with a rich middleware or protocol stack ecosystem that benefit from independent versioning and community contributions, without the overhead of a full registry. It works well when the team is comfortable with Git-based workflows and willing to invest in CI and onboarding tooling.

The component registry model
The component registry model is the most scalable architecture for large ecosystems and the most expensive one to operate. Individual middleware components are published to a central package index with semantic versioning. Component manifests declare their dependencies. The build system resolves the dependency graph at configuration time, downloads the required versions, and writes a lockfile pinning the resolved set into the application’s source control.
What this unlocks is genuinely different in kind, not just degree, from the meta-tool model.
Independent release cycles for individual components mean that a fix to one driver does not require re-releasing the entire SDK. Component authors ship on their own cadence, and consumers pick up updates when they choose to.
Third-party component publication becomes a first-class workflow. A community contributor authors a driver, publishes it to the registry, and customers can pull it into their application with a single dependency declaration. The vendor’s role shifts from gatekeeper to indexer and reviewer.
Conditional dependency declarations let a component declare that it requires another component only when a specific Kconfig symbol is enabled. This eliminates a category of dependency bloat that monolithic and even meta-tool SDKs struggle with.
Lockfile generation provides reproducible builds without the opacity of raw SHA pinning. The lockfile records the resolved versions in a human-readable, machine-parseable form, checked into the application’s repository. Builds across teams and across CI environments resolve to the same component set, deterministically.
The downsides are also real and require sustained investment.
Governance overhead for reviewing and indexing third-party contributions is non-trivial, and teams who treat it as someone’s part-time responsibility find that the registry quality degrades within a year.
Poorly tagged breaking changes can silently break downstream consumers. A component author who increments a minor version on what should have been a major version triggers cascading failures across applications that pinned only to the major version. The vendor has to enforce semver discipline through automated checks and explicit policy.
Dependency graph conflicts can be non-trivial for developers unfamiliar with package management, and the diagnostic experience for “component A wants version 2.x of component C, component B wants version 3.x” is a known sore point in every package ecosystem.
Offline environments may require additional mirroring infrastructure. Customers in regulated or air-gapped environments cannot pull from a public registry on demand, and the SDK team has to provide a sanctioned mechanism for snapshotting the registry into an offline cache.
Community-published components introduce security risks. A registry without code review, signing, or provenance metadata is a supply-chain vulnerability. Mature registries invest in component signing, build provenance, and CVE tracking — none of which is cheap.
The component registry model is the right choice for large, multi-vendor, or fast-growing ecosystems where automatic dependency resolution, third-party contributions, and reproducible builds are priorities. It is a poor fit for early-stage projects or for vendors who cannot commit to the governance investment.
A decision framework
The choice between the three models is genuinely a function of where the SDK and its ecosystem are, not which model is technically purest.
The monolithic package fits narrow, stable product families with small teams and a small customer base. It is the right answer for the first two or three years of a new platform. The cost of operating it is low, and the simplicity benefit accrues to both the SDK team and the customers.
The meta-tool model fits SDKs with a growing middleware or protocol stack ecosystem, where independent component versioning starts to matter, but where a full registry’s governance overhead is not yet justified. It is the architecturally preferred middle ground for the long stretch of platform maturity between “small and stable” and “large and self-sustaining.”
The component registry model fits ecosystems that have outgrown the meta-tool’s coordination overhead — where third-party contributions are a strategic priority, where the customer base is large enough to amortise the governance investment, and where automatic dependency resolution is producing more value than the resolver’s failure modes are costing.
Two organisational signals are worth watching. If the SDK team is spending more than ten percent of its time mirroring, vendoring, or coordinating cross-repository changes, the meta-tool model is starting to underperform. If the registry’s governance backlog is growing faster than the registry team can review, the registry model is over-extended and needs more investment or a tighter scope.
The migration question
Migration between models is possible but not free. Moving from monolithic to meta-tool requires decomposing the archive into independently maintainable repositories, establishing a manifest format, and migrating customer build environments. Moving from meta-tool to registry requires defining a component manifest schema, building an index, establishing a publication workflow, and re-versioning every component to clean semantic-version-compliant releases.
Each migration takes a year or more in practice, and during the migration the SDK ships against both models simultaneously, doubling the test matrix. This is the strongest argument for choosing deliberately rather than defaulting: the model you start with is the one you will operate for several years before you can credibly leave it.
One thing that helps is treating the build system as part of the public API from day one. Component names, CMake target names, Kconfig symbol names, manifest schema, and registry component identifiers are all public surface. A breaking change to any of them is a breaking change to the SDK, regardless of whether the C API is unchanged. SDKs that version this surface from the first release have a much easier migration path than SDKs that retrofit versioning onto names that customers have already taken dependencies on.

The cost of defaulting
The deepest cost of staying on the wrong delivery model is not technical. It is that the SDK’s release cadence, governance model, and community story are all shaped by the packaging choice. A monolithic SDK cannot have a thriving third-party component ecosystem, no matter how good the underlying architecture is, because the model does not have a place to put third-party components. A meta-tool SDK cannot offer the dependency resolution experience that customers in fast-moving ecosystems now expect, no matter how well the manifests are maintained. A registry SDK cannot operate without sustained governance investment, no matter how clean the technical implementation is.
The packaging model is where the technical architecture meets the operating model. Choosing it deliberately, and migrating between models when the platform clearly demands it, is one of the highest-leverage decisions an SDK lead can make. Defaulting into one and discovering the cost three years later is one of the most common ways embedded SDKs accumulate the kind of technical debt that becomes a barrier to adoption — the kind that is invisible in the architecture diagram and obvious in the design-win pipeline.
Choosing how to ship your SDK is one of the few decisions that’s hard to reverse.
needCode helps embedded teams design and migrate SDK delivery models that scale with their platform, from first release through to multi-vendor ecosystem. If you’re evaluating your packaging architecture, let’s talk.
Book a free discovery call or get in touch
Further reading
- Anatomy of a Production OTA Pipeline — a worked example of the kind of SDK component each delivery model has to ship, version, and maintain reliably
- Documentation as a Product — how the same release discipline that applies to packaging applies to the documentation surface customers interact with first
- FreeRTOS / Zephyr OS — Zephyr’s west tool is the most widely deployed instance of the meta-tool model described in this post
- Firmware Security — the supply-chain and signing considerations that become critical when moving to a component registry model

