CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-pulumi--pulumi

Pulumi's Node.js SDK for infrastructure-as-code platform that allows you to create, deploy, and manage infrastructure using familiar programming languages and tools.

85

1.02x
Overview
Eval results
Files

output-system.mddocs/

Output System

Pulumi's Output system provides async value management with dependency tracking, enabling safe composition of promises and resource dependencies throughout infrastructure code. Outputs represent values that may not be available until deployment time.

Core Output Types

abstract class Output<T> {
  apply<U>(func: (t: T) => Input<U>): Output<U>;
  readonly isKnown: Promise<boolean>;
  readonly isSecret: Promise<boolean>;
}

interface OutputInstance<T> extends Output<T> {
  __pulumiOutput: true;
}

type Input<T> = T | Promise<T> | OutputInstance<T>;
type Inputs = Record<string, Input<any>>;

type Unwrap<T> = T extends OutputInstance<infer U> ? U :
  T extends Promise<infer U> ? U : T;

type UnwrappedObject<T> = {
  [K in keyof T]: Unwrap<T[K]>;
};

type Lifted<T> = {
  [K in keyof T]: Output<T[K]>;
};

Core Output Functions

function output<T>(val: Input<T>): Output<Unwrap<T>>;
function secret<T>(val: Input<T>): Output<Unwrap<T>>;
function unsecret<T>(val: Input<T>): Output<Unwrap<T>>;
function isSecret<T>(val: Output<T>): Promise<boolean>;

function all<T>(values: T): Output<UnwrappedObject<T>>;
function concat(...params: Input<any>[]): Output<string>;
function interpolate(literals: TemplateStringsArray, ...placeholders: Input<any>[]): Output<string>;

function jsonStringify(val: Input<any>, replacer?: any, space?: Input<string | number>): Output<string>;
function jsonParse<T>(text: Input<string>, reviver?: any): Output<T>;

Utility Functions

function deferredOutput<T>(): { output: Output<T>; setter: (value: Input<T>) => void };
function getAllResources<T>(op: Output<T>): Resource[];
function isSecretOutput<T>(o: any): o is Output<T>;
function isUnknown(val: any): boolean;
function containsUnknowns(value: any): boolean;

Error Classes

class OutputToStringError extends Error {
  constructor(message: string);
}

class Unknown {
  readonly isKnown: false;
  readonly isSecret: false;
}

Usage Examples

Basic Output Creation

import * as pulumi from "@pulumi/pulumi";

// Create output from values
const simpleOutput = pulumi.output("hello");
const promiseOutput = pulumi.output(Promise.resolve(42));

// Create secret outputs
const secretOutput = pulumi.secret("my-secret-value");
const secretFromConfig = new pulumi.Config().requireSecret("apiKey");

Output Transformation

import * as pulumi from "@pulumi/pulumi";

const bucket = new aws.s3.Bucket("my-bucket");

// Transform a single output
const bucketUrl = bucket.id.apply(id => `https://${id}.s3.amazonaws.com`);

// Chain transformations
const processedName = bucket.id
  .apply(id => id.toLowerCase())
  .apply(id => id.replace(/-/g, "_"));

// Handle async transformations
const bucketSize = bucket.id.apply(async (id) => {
  const response = await getBucketSize(id);
  return response.size;
});

Combining Multiple Outputs

import * as pulumi from "@pulumi/pulumi";

const bucket = new aws.s3.Bucket("my-bucket");
const distribution = new aws.cloudfront.Distribution("cdn", {
  // ... config
});

// Combine multiple outputs into object
const combined = pulumi.all({
  bucketName: bucket.id,
  distributionId: distribution.id,
  region: aws.getRegion().then(r => r.name),
}).apply(({ bucketName, distributionId, region }) => ({
  url: `https://${distributionId}.cloudfront.net`,
  bucket: bucketName,
  region: region,
}));

// Combine into array
const urls = pulumi.all([
  bucket.websiteEndpoint,
  distribution.domainName,
]).apply(([bucketUrl, cdnUrl]) => ({
  direct: `http://${bucketUrl}`,
  cdn: `https://${cdnUrl}`,
}));

String Interpolation

import * as pulumi from "@pulumi/pulumi";

const bucket = new aws.s3.Bucket("my-bucket");
const region = aws.getRegion();

// Template string interpolation
const bucketUrl = pulumi.interpolate`https://${bucket.id}.s3.${region.name}.amazonaws.com`;

// Complex interpolation
const configHtml = pulumi.interpolate`
<configuration>
  <bucket>${bucket.id}</bucket>
  <region>${region.name}</region>
  <timestamp>${Date.now()}</timestamp>
</configuration>`;

Concatenation

import * as pulumi from "@pulumi/pulumi";

const prefix = pulumi.output("prod");
const suffix = pulumi.output("db");

// Simple concatenation
const resourceName = pulumi.concat(prefix, "-", suffix);

// With multiple inputs
const fullPath = pulumi.concat(
  "/api/v1/",
  prefix,
  "/",
  suffix,
  "/config"
);

JSON Operations

import * as pulumi from "@pulumi/pulumi";

const config = pulumi.all({
  database: {
    host: "localhost",
    port: 5432,
  },
  cache: {
    host: "redis.example.com",
    port: 6379,
  },
});

// Convert to JSON string
const configJson = pulumi.jsonStringify(config, null, 2);

// Parse JSON string
const jsonString = pulumi.output('{"key": "value", "number": 42}');
const parsed = pulumi.jsonParse<{key: string; number: number}>(jsonString);

Secret Handling

import * as pulumi from "@pulumi/pulumi";

const config = new pulumi.Config();
const dbPassword = config.requireSecret("dbPassword");

// Check if output is secret
const isSecretCheck = pulumi.isSecret(dbPassword); // Promise<boolean>

// Combine secret with non-secret (result is secret)
const connectionString = pulumi.interpolate`postgresql://user:${dbPassword}@localhost:5432/mydb`;

// Remove secret marking (use carefully!)
const plainPassword = pulumi.unsecret(dbPassword);

Deferred Outputs

import * as pulumi from "@pulumi/pulumi";

// Create deferred output for complex initialization
const { output: deferredValue, setter: setValue } = pulumi.deferredOutput<string>();

// Set value later (perhaps after async operation)
async function initializeValue() {
  const result = await someAsyncOperation();
  setValue(result);
}

initializeValue();

// Use the deferred output
export const finalValue = deferredValue;

Working with Unknown Values

import * as pulumi from "@pulumi/pulumi";

// During preview, some values are unknown
const bucket = new aws.s3.Bucket("my-bucket");

bucket.id.apply(id => {
  if (pulumi.isUnknown(id)) {
    console.log("Bucket ID is unknown during preview");
    return "preview-placeholder";
  }
  return `Bucket ID: ${id}`;
});

// Check for unknowns in complex objects
const configObject = { 
  bucketId: bucket.id,
  region: "us-east-1" 
};

if (pulumi.containsUnknowns(configObject)) {
  console.log("Config contains unknown values");
}

Resource Dependencies

import * as pulumi from "@pulumi/pulumi";

const bucket = new aws.s3.Bucket("my-bucket");

// Get all resources that an output depends on
const dependencies = pulumi.getAllResources(bucket.id);
console.log(`Bucket ID depends on ${dependencies.length} resources`);

// Outputs automatically track dependencies
const bucketPolicy = new aws.s3.BucketPolicy("policy", {
  bucket: bucket.id, // This creates a dependency
  policy: bucket.arn.apply(arn => JSON.stringify({
    Version: "2012-10-17",
    Statement: [{
      Effect: "Allow",
      Principal: "*",
      Action: "s3:GetObject",
      Resource: `${arn}/*`
    }]
  }))
});

Best Practices

  • Use apply() for transforming single outputs
  • Use all() for combining multiple outputs
  • Use interpolate for string templates with outputs
  • Mark sensitive data as secrets with secret()
  • Handle unknown values gracefully in preview mode
  • Avoid blocking operations in output transformations
  • Chain transformations instead of nesting apply() calls
  • Use TypeScript generics to maintain type safety through transformations

Install with Tessl CLI

npx tessl i tessl/npm-pulumi--pulumi

docs

asset-management.md

automation.md

configuration.md

dynamic-resources.md

index.md

logging-diagnostics.md

output-system.md

provider-development.md

resource-management.md

runtime-operations.md

stack-references.md

utilities.md

tile.json