CONCEPT Cited by 1 source
Shim layer¶
Definition¶
A shim layer is a thin proxy library interposed between application code and one or more underlying implementations, exposing a single unified API and dispatching each call to the chosen backend.
In a dual-stack migration — the canonical motivating case on this wiki — the shim sits between application code and two copies of the same library (e.g. legacy and upstream) that are statically linked together in the same binary, with a runtime flag (flavor) choosing which backend handles each call. See concepts/runtime-flavor-dispatch.
Why a shim¶
A shim decouples two concerns:
- Stability for consumers — existing call sites at higher
layers continue to target a stable API (often the library's own
namespace, e.g.
webrtc::), with no code changes required when the underlying implementation is swapped or forked. - Flexibility for the migration — the shim can dispatch to any of N backends based on runtime configuration, enabling A/B testing, gradual rollout, easy rollback, or multi-backend coexistence (e.g. for hardware-specific variants).
Where to shim matters¶
The layer at which you interpose has order-of-magnitude cost consequences. From Meta's WebRTC case study:
"This approach — shimming at the lowest possible layer — avoids a significant binary size regression that duplicating the higher-layer call orchestration library would have caused. Duplication would have resulted in an uncompressed size increase of approximately 38 MB, whereas our solution added only about 5 MB — an 87% reduction." (sources/2026-04-09-meta-escaping-the-fork-webrtc-modernization)
Shimming too high duplicates orchestration code; shimming too low
doesn't capture enough surface area to support the migration. The
right layer is just below the library-under-migration but above
its consumer — in WebRTC's case, between webrtc::* and the
call-orchestration library.
Components of a well-formed shim¶
Meta's WebRTC shim illustrates the canonical shape:
- Unified API — a single version-agnostic API every caller
uses (e.g.
webrtc_shim::Foo). - Runtime flavor dispatch — a global enum or config flag set
at app startup decides between
webrtc_legacy::*andwebrtc_latest::*per-call. - Directional adapters — proxy objects that implement the unified API and forward to the underlying flavor, or vice-versa (exposing internal backend classes outward, or injecting custom components inward).
- Directional converters — utility functions that translate structs/enums between the shim type system and the backend type system.
- Template-based shared logic — the common code path lives in generic templates; per-flavor behavior lives in template specializations, so divergence cost is paid only where the flavors actually differ.
- Backward compatibility header — usually via
bulk
usingdeclarations so existing call sites don't need to be rewritten.
What the shim doesn't fix¶
A shim does not remove the need to resolve
ODR violations when two copies of the
library are statically linked. That's solved separately via
symbol renamespacing (rewriting
webrtc:: → webrtc_latest:: / webrtc_legacy:: across the code)
and by merging/suffixing non-namespaced globals, macros, and free
variables. The shim sits on top of that renamespacing work.
Seen in¶
- sources/2026-04-09-meta-escaping-the-fork-webrtc-modernization — canonical wiki instance. systems/meta-webrtc-shim interposes between Meta application code and two coexisting WebRTC implementations across 50+ RTC use cases.
Related¶
- concepts/runtime-flavor-dispatch — the dispatch mechanism a shim uses when it has multiple backends.
- concepts/odr-violation — the C++ linker problem a dual-stack shim must solve alongside the shim layer itself.
- concepts/symbol-renamespacing — the mechanical enabler of dual-copy coexistence.
- patterns/shim-for-dual-stack-ab-testing — the pattern that uses a shim to enable per-call A/B testing of two library versions.