You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Document Component Args type requirements and limitations (#16328)
* Document Component Args type requirements and limitations
This change addresses issue #15682 by documenting the type requirements
and limitations for Component Args classes in multi-language components.
Changes:
- Added comprehensive new section "Component arguments and type requirements"
to the Components concepts page covering:
- Serialization requirements and why they're needed
- Supported types (primitives, arrays, objects, Input wrappers)
- Unsupported types (union types, functions, complex generics)
- Language-specific constructor requirements for TypeScript, Python,
Go, .NET, and Java based on technical details from @julienp
- Best practices for designing component arguments
- Enhanced Build a Component guide with cross-references from all
language sections (TypeScript, Python, Go, C#, Java) that mention
"serializable" to link to the comprehensive documentation
- Included concrete TypeScript example showing unsupported types
(union types, functions) vs. supported patterns
This ensures developers understand the constraints when authoring
multi-language components and can avoid common pitfalls with
unsupported types.
Fixes#15682
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* Apply style guide fixes to component args documentation
- Add ending punctuation to list items in supported/unsupported types sections
- Replace passive voice with active voice in serialization description
- Replace "simple" with "basic" per style guidelines
- Add periods to all best practices list items for consistency
Co-authored-by: Cam Soper <[email protected]>
* Review feedback
* Update content/docs/iac/concepts/components/_index.md
Co-authored-by: Josh Kodroff <[email protected]>
---------
Co-authored-by: Claude <[email protected]>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Cam Soper <[email protected]>
Co-authored-by: Josh Kodroff <[email protected]>
Copy file name to clipboardExpand all lines: content/docs/iac/concepts/components/_index.md
+175Lines changed: 175 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -126,6 +126,181 @@ A component resource must register a unique type name with the base constructor.
126
126
For a complete end-to-end walkthrough of building a component from scratch, including setup, implementation, and publishing, see the [Build a Component](/docs/iac/using-pulumi/build-a-component/) guide.
127
127
{{< /notes >}}
128
128
129
+
## Component arguments and type requirements
130
+
131
+
When authoring components that will be consumed across different languages (multi-language components), the arguments class has specific requirements and limitations due to the need for serialization. These constraints ensure that component arguments can be transmitted to the Pulumi engine and reconstructed across language boundaries.
132
+
133
+
### Serialization requirements
134
+
135
+
Component arguments must be serializable, meaning you must convert them to a format that the engine can transmit and reconstruct. This is necessary because:
136
+
137
+
1. The Pulumi engine needs to understand and validate the inputs
138
+
1. Multi-language components need to translate arguments between languages
139
+
1. The state needs to be stored and retrieved across deployments
140
+
141
+
### Supported types
142
+
143
+
The following types are supported in component arguments:
-**Objects/maps**: Objects with properties of supported types.
148
+
-**Input wrappers**: Language-specific input types that wrap values:
149
+
- TypeScript/JavaScript: `pulumi.Input<T>`
150
+
- Python: `pulumi.Input[T]`
151
+
- Go: `pulumi.StringInput`, `pulumi.IntInput`, etc.
152
+
- .NET: `Input<T>`
153
+
- Java: `Output<T>`
154
+
155
+
### Unsupported types
156
+
157
+
The following types are not supported in component arguments:
158
+
159
+
-**Union types**: TypeScript union types like `string | number` are not supported due to limitations in schema inference.
160
+
-**Functions/callbacks**: Functions cannot be used in component arguments as they cannot be represented in the schema.
161
+
-**Platform-specific types**: Types that exist only in one language and cannot be translated.
162
+
163
+
### Design recommendations
164
+
165
+
For better usability and maintainability:
166
+
167
+
-**Avoid deeply nested types**: While complex generic types can be serialized, deeply nested structures make components harder to use and understand. Keep argument structures simple and flat when possible.
168
+
169
+
**Example of unsupported TypeScript types:**
170
+
171
+
```typescript
172
+
// ❌ This will NOT work - union types are not supported
173
+
exportinterfaceMyComponentArgs {
174
+
value:string|number; // Union type - unsupported
175
+
callback: () =>void; // Function - unsupported
176
+
}
177
+
178
+
// ✅ This WILL work - use primitives or Input types
179
+
exportinterfaceMyComponentArgs {
180
+
value:pulumi.Input<string>;
181
+
count:pulumi.Input<number>;
182
+
}
183
+
```
184
+
185
+
### Constructor requirements by language
186
+
187
+
Each language has specific requirements for component constructors to ensure proper schema generation:
188
+
189
+
{{< chooser language "typescript,python,go,csharp,java" >}}
190
+
191
+
{{% choosable language typescript %}}
192
+
193
+
**Requirements:**
194
+
195
+
- The constructor must have an argument named exactly `args`
196
+
- The `args` parameter must have a type declaration (e.g., `args: MyComponentArgs`)
1.**Wrap all scalar members in Input types**: Every scalar argument should be wrapped in the language's input type (e.g., `pulumi.Input<string>`). This allows users to pass both plain values and outputs from other resources, avoiding the need to use `apply` for resource composition.
299
+
1.**Use basic types**: Stick to primitive types, arrays, and basic objects.
300
+
1.**Avoid union types**: Instead of a single value with multiple types, consider multiple, mutually exclusive argument members and validate that only one of them has a value in your component constructor.
301
+
1.**Document required vs. optional**: Clearly document which arguments are required and which have defaults.
302
+
1.**Follow language conventions**: Use camelCase for schema properties but follow language-specific naming in implementation (snake_case in Python, PascalCase in .NET).
303
+
129
304
## Creating Child Resources
130
305
131
306
Component resources often contain child resources. The names of child resources are often derived from the component resources's name to ensure uniqueness. For example, you might use the component resource's name as a prefix. Also, when constructing a resource, children must be registered as such. To do this, pass the component resource itself as the `parent` option.
Note that argument classes must be *serializable* and use `pulumi.Input` types, rather than the language's default types.
668
+
Note that argument classes must be *serializable* and use `pulumi.Input` types, rather than the language's default types. Certain types like union types (e.g., `string | number`) and functions are not supported due to schema inference limitations. For details on type requirements and limitations, see [Component arguments and type requirements](/docs/iac/concepts/components/#component-arguments-and-type-requirements).
669
669
670
670
{{% /choosable %}}
671
671
@@ -679,7 +679,7 @@ class StaticPageArgs(TypedDict):
679
679
"""The HTML content for index.html."""
680
680
```
681
681
682
-
Note that argument classes must be *serializable* and use `pulumi.Input` types, rather than the language's default types.
682
+
Note that argument classes must be *serializable* and use `pulumi.Input` types, rather than the language's default types. This means certain types like union types and functions are not supported. For details on type requirements and limitations, see [Component arguments and type requirements](/docs/iac/concepts/components/#component-arguments-and-type-requirements).
683
683
684
684
Python class properties are typically written in lowercase with words separated by underscores, known as [`snake_case`](https://en.wikipedia.org/wiki/Snake_case), however properties in the [Pulumi package schema](https://www.pulumi.com/docs/iac/using-pulumi/extending-pulumi/schema/) are usually written in [`camelCase`](https://en.wikipedia.org/wiki/Camel_case), where capital letters are used to separate words. To follow these conventions, the inferred schema for a component will have translated property names. In our example `index_content` will become `indexContent` in the schema. When using a component, the property names will follow the conventions of that language, for example if we use our component from TypeScript, we would refer to `indexContent`, but if we use it from Python, we would use `index_content`.
685
685
@@ -694,7 +694,7 @@ type StaticPageArgs struct {
694
694
}
695
695
```
696
696
697
-
Note that argument classes must be *serializable* and use `pulumi.Input` types, rather than the language's default types.
697
+
Note that argument classes must be *serializable* and use `pulumi.Input` types, rather than the language's default types. This means complex or platform-specific types may not be supported. For details on type requirements and limitations, see [Component arguments and type requirements](/docs/iac/concepts/components/#component-arguments-and-type-requirements).
698
698
699
699
Go struct fields are typically written in title case, with the first letter capitalized and capital letters used to separate words, however properties in the [Pulumi package schema](https://www.pulumi.com/docs/iac/using-pulumi/extending-pulumi/schema/) are usually written in [`camelCase`](https://en.wikipedia.org/wiki/Camel_case), with the first letter in lowercase and capital letters used to separate words. To follow these conventions, the inferred schema for a component will have translated property names. In our example `IndexContent` will become `indexContent` in the schema. When using a component, the property names will follow the conventions of that language, for example if we use our component from TypeScript, we would refer to `indexContent`, but if we use it from Go, we would use `IndexContent`.
700
700
@@ -711,7 +711,7 @@ public sealed class StaticPageArgs : ResourceArgs {
711
711
}
712
712
```
713
713
714
-
Note that argument classes must be *serializable* and use `Pulumi.Input` types, rather than the language's default types.
714
+
Note that argument classes must be *serializable* and use `Pulumi.Input` types, rather than the language's default types. This means complex or platform-specific types may not be supported. For details on type requirements and limitations, see [Component arguments and type requirements](/docs/iac/concepts/components/#component-arguments-and-type-requirements).
715
715
716
716
{{% /choosable %}}
717
717
@@ -737,7 +737,7 @@ class StaticPageArgs extends ResourceArgs {
737
737
}
738
738
```
739
739
740
-
Note that argument classes must be *serializable* and use `com.pulumi.core.Output<T>` types, rather than the language's default types.
740
+
Note that argument classes must be *serializable* and use `com.pulumi.core.Output<T>` types, rather than the language's default types. This means complex or platform-specific types may not be supported. For details on type requirements and limitations, see [Component arguments and type requirements](/docs/iac/concepts/components/#component-arguments-and-type-requirements).
741
741
742
742
The `@Import` decorator marks this as a *required* input and allows use to give a name for the input that could be different from the implementation here.
0 commit comments