---
# System prepended metadata

title: Proposal for S2 "Spin Composition Feature" work

---

# Brainstorm S2 "Spin Composition Feature Work"

This is a pre-propsal for re-igniting efforts to surface component composition as a first class feature of Spin. 

## Background

Near the end of last year, we attempted to implement a feature for Spin called [Component Imports](https://github.com/fermyon/spin/pull/1804) where the purpose was to equip Spin developers with the ability to express composable relationships between components in their application manifest. The linked SIP proposed a simple DX for expressing how exports of a component can be used to satisfy the imports of another. However, while implementing the POC we found that `wasm-compose` in it's current state was lacking certain features (namely complete resource support) and `wac` was still under active design and development.

Since then, `wac` has stablized and has recently shipped with a programmatic API making it possible  to rekindle the efforts of bringing composition to Spin. However, there is an important discussion (following section) to be had around how we want to implement composition in Spin.

## Discussion

The SIP for `Component Imports` as a means to express the DX required to enable composition is still largely relevant. The complexity of this feature lies within how we go about implementing. As pointed out in the SIP linked above, there are roughly two forms of composition that we should consider: `static` OR `dynamic`.

### Static

`static` composition refers to the idea that composition happens AOT (specifically before component instantiation).
This would occur as late as possible in the process of setting up the trigger during `spin up`. Using `wac_graph` this should now be made entirely possible. 

The main benefit to static composition is performance. From SIP (rylev): 
> there's a penalty paid for exiting the guest and entering the host. Static composition avoids this cost since > both components are now the same 1 guest component instead of two separate guest instances.

The main complexity of static composition is the "virtualization" of Spin capabilities. When two components are composed there is an "implicit propagation of imports" whereby shared imports that are not satisfied by composition are lifted up to the root component and then the composed components (now sub-components of the root) are instantiated with the singular imported instance for the shared import. The implication of this is we can no longer isolate the capabilities from the manifest that two components being composed together define now that there is a single shared import. 

This complexity suggests a significant amount of pre-requisite work to build `spin-virt` which would enable us to appropriately virtualize spin imports in a way that requests for things like opening a key-value store would be allow/deny listed against the capabilities defined in a Spin.toml.

### Dynamic
`dynamic` composition refers to the idea that ABI calls are actually routed through the Spin host. Instead of components being composed AOT (pre trigger up), the import-export relationship between two "composed" components is satisfied by providing the Linker with implementations that close over the app state to proxy calls between component instances.

The obvious benefit of `dynamic` composition is that we can side step "virtualization" complexities. I.e. We retain the ability to keep each component instance's capabilities (accessed via imports, e.g. "key value stores") isolated from other components that are part of the "virtual composition DAG".

The hand-wavy downside (because without perf numbers) is the performance penalty for having to involve the host in routing calls between components.

**Open Question / Seeking Clarity**: (From SIP) If we go the route of dynamic composition each component instance requires its own store; is it possible to pass resource arguments between calls?

**Another Consideration**: We have to be careful to not break component invariants while implementing dynamic composition (namely reentrancy). This should be possible by doing a simple cycle detection on the `Spin.toml`.

## Recommendation

I feel fairly confident at this point suggesting the we pursue dynamic composition to enable this feature. As this is largely an implementation detail abstracted behind the component imports DX, we could in the future support both static and dynamic composition, or reimplement the path not chosen if we see an obvious reason to. However, the goal (AFAIU) for this season would be to deliver to Spin developers the ability to express how their Spin components depend on eachother.

## Other possible questions

1. What are potential customers actually asking for?
2. What kind of time investment are we looking at to integrate this feature into the various Spin embeddings?
3. What is the measure of success for this project in a seasons effort?
4. Are we all in agreement with the idea that composition should be expressable in a Spin.toml as opposed to improving the DX of `wac` (or other ideas)?