1. The Silo Problem#
In Episode 7, we wrote a SecureBucket class in TypeScript. We distributed it via NPM.
// Inside an NPM Package: @my-org/infra
export class SecureBucket extends pulumi.ComponentResource { ... }If a Python developer tries to pip install my-org-infra, they cannot use the SecureBucket class, because the Python runtime has absolutely no idea how to execute TypeScript.
To solve this, the Platform Team would historically have to write the exact same SecureBucket logic a second time in Python, and a third time in Go. This is a maintenance nightmare.
2. Enter Multi-Language Components (MLC)#
Pulumi MLC solves this by shifting the architecture.
Instead of distributing raw source code via NPM or PyPI, you distribute a Pulumi Provider Plugin (a compiled binary).
How it Works:#
- You author the
SecureBucketcomponent in TypeScript. - You run the
pulumi package gen-sdkcommand. - Pulumi analyzes your TypeScript classes and generates a standard gRPC schema.
- From that schema, Pulumi automatically generates strongly-typed wrapper SDKs for Python, Go, C#, and Java.
- The Python developer installs the generated Python SDK. When they call
SecureBucket()in Python, the Python SDK sends a gRPC request to the Pulumi Engine. - The Pulumi Engine boots up a hidden Node.js runtime, executes your original TypeScript logic, and returns the result back to Python!
3. Practice: Building an MLC Provider#
Authoring an MLC is more complex than a standard Pulumi project. It requires a specific directory structure and scaffolding.
Step 1: The Schema#
The foundation of an MLC is the schema.json file. This tells Pulumi exactly what arguments your component accepts and what outputs it returns, in a language-agnostic format.
{
"name": "my-org-infra",
"version": "1.0.0",
"resources": {
"my-org-infra:index:SecureBucket": {
"isComponent": true,
"inputProperties": {
"bucketName": {
"type": "string"
}
},
"properties": {
"bucketArn": {
"type": "string"
}
}
}
}
}Step 2: The TypeScript Implementation#
You implement the logic exactly as we did in Episode 7, but you wrap it inside a Provider class that listens for gRPC requests from the Pulumi Engine.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as provider from "@pulumi/pulumi/provider";
class SecureBucket extends pulumi.ComponentResource {
public readonly bucketArn: pulumi.Output<string>;
constructor(name: string, args: any, opts?: pulumi.ComponentResourceOptions) {
super("my-org-infra:index:SecureBucket", name, args, opts);
const bucket = new aws.s3.Bucket(name, {
bucket: args.bucketName,
acl: "private",
}, { parent: this });
this.bucketArn = bucket.arn;
this.registerOutputs({ bucketArn: this.bucketArn });
}
}
// The gRPC Provider Server
export function construct(
name: string,
type: string,
inputs: pulumi.Inputs,
options: pulumi.ComponentResourceOptions
): Promise<provider.ConstructResult> {
if (type === "my-org-infra:index:SecureBucket") {
const component = new SecureBucket(name, inputs, options);
return Promise.resolve({
urn: component.urn,
state: { bucketArn: component.bucketArn },
});
}
throw new Error(`Unknown component type ${type}`);
}Step 3: Generating the SDKs#
Once the implementation is complete, you use the Pulumi CLI to automatically generate the Python, Go, and C# client libraries!
# Generate the Python SDK
pulumi package gen-sdk schema.json --language python
# Generate the Go SDK
pulumi package gen-sdk schema.json --language goYou can now publish the Python SDK to PyPI, the Go SDK to GitHub, and the Node SDK to NPM.
4. Consuming the MLC (Python Perspective)#
Now, look at the world from the Data Science team’s perspective. They do not know or care that the SecureBucket logic was written in TypeScript.
They write standard Python IaC:
import pulumi
# They import the auto-generated SDK!
import pulumi_my_org_infra as my_org
# They get full IDE auto-completion for bucket_name
secure_bucket = my_org.SecureBucket("data-bucket",
bucket_name="my-company-data"
)
pulumi.export("bucket_arn", secure_bucket.bucket_arn)When they run pulumi up, the gRPC translation happens silently in the background.
Conclusion#
Congratulations! You have completed the Pulumi series.
You have journeyed from the basics of initializing a stack (Episode 1), mastering the complexities of asynchronous Promises (Episode 5), building reusable Enterprise Components (Episode 7), and writing offline Unit Tests in Jest (Episode 13).
Finally, you learned how to break down language silos entirely using Multi-Language Components.
By leveraging general-purpose programming languages like TypeScript, you have transcended standard configuration management. You are now writing true Software for Infrastructure.
Thank you for following along with the Pulumi learning path!

