Summary
When multiple features dependOn the same feature with different option values, the Dev Container CLI treats them as different features and installs them separately. This behavior is problematic for features that are not idempotent (like the homebrew feature).
Problem
According to the specification, features with different options are considered "not equal" and will both be added to the installation list. This works fine for idempotent features, but breaks for features that cannot be installed multiple times with different parameters.
Example Scenario
// devcontainer-feature.json for bun feature
{
"id": "bun",
"dependsOn": {
"./features/homebrew": {
"packages": ["oven-sh/bun/bun"]
}
}
}
// devcontainer-feature.json for gascity feature
{
"id": "gascity",
"dependsOn": {
"./features/homebrew": {
"packages": ["gastownhall/gascity/gascity"]
}
}
}
In this case, only one of the packages gets installed (typically the first one in the dependency graph), and the homebrew feature is not designed to be installed multiple times with different package lists.
Proposed Solution
Add support for merging options when multiple features depend on the same feature:
- Option Merging: When multiple features depend on the same feature, merge their options instead of treating them as separate instances
- Array-based merging: For array-type options (like
packages), concatenate the arrays
- Override conflict resolution: For scalar options, either:
- Use the first value (current behavior but explicit)
- Throw an error if there's a conflict
- Add a new merge strategy annotation
Example of desired behavior:
// Input: two features depend on homebrew with different packages
bun → homebrew: { packages: ["oven-sh/bun/bun"] }
gascity → homebrew: { packages: ["gastownhall/gascity/gascity"] }
// Desired output: merged options
homebrew: { packages: ["oven-sh/bun/bun", "gastownhall/gascity/gascity"] }
Alternatives Considered
- Document current behavior as limitation: Accept that dependsOn cannot be used for features with different parameters
- Require manual consolidation: Force users to manually specify all packages in a single feature call
- Add merge strategy annotation: Allow feature authors to specify how options should be merged
Additional Context
This is particularly important for package manager features (homebrew, apt, npm, etc.) where users want to combine multiple package installations in a devcontainer while keeping the configuration modular and reusable.
Current workaround is to specify all packages in a single feature call:
{
"features": {
"./features/homebrew": {
"packages": ["gastownhall/gascity/gascity", "oven-sh/bun/bun"]
}
}
}
But this loses the modularity and reusability that dependsOn was meant to provide.
Summary
When multiple features
dependOnthe same feature with different option values, the Dev Container CLI treats them as different features and installs them separately. This behavior is problematic for features that are not idempotent (like the homebrew feature).Problem
According to the specification, features with different options are considered "not equal" and will both be added to the installation list. This works fine for idempotent features, but breaks for features that cannot be installed multiple times with different parameters.
Example Scenario
In this case, only one of the packages gets installed (typically the first one in the dependency graph), and the homebrew feature is not designed to be installed multiple times with different package lists.
Proposed Solution
Add support for merging options when multiple features depend on the same feature:
packages), concatenate the arraysExample of desired behavior:
Alternatives Considered
Additional Context
This is particularly important for package manager features (homebrew, apt, npm, etc.) where users want to combine multiple package installations in a devcontainer while keeping the configuration modular and reusable.
Current workaround is to specify all packages in a single feature call:
{ "features": { "./features/homebrew": { "packages": ["gastownhall/gascity/gascity", "oven-sh/bun/bun"] } } }But this loses the modularity and reusability that
dependsOnwas meant to provide.