cswork / libraryOpen practice workspace

Articles

Pulumi Interview Questions: Outputs, Preview Behavior, and Secret Handling

Prepare for Pulumi interviews with precise Output reasoning, preview-time unknowns, resource visibility, and secret propagation without unsafe logging.

Pulumi interview questions often look like TypeScript questions but test an infrastructure graph. An Output<T> is not merely a delayed T: it carries a value that may be unknown during preview, dependencies on resources, and whether the value is secret. Your answer should predict all three properties before proposing code.

This guide uses current Pulumi documentation and an original local model with eight checks. The model reproduces reasoning rules; it does not run Pulumi, contact a provider, or create cloud resources. Start with Design Safe Configuration and Deployment for Hundreds of Services to connect dependency reasoning to rollout safety.

Read an Output as more than a Promise

Official behavior: Pulumi Inputs and Outputs let the engine track resource dependencies. A resource output can be passed directly to another resource input, allowing Pulumi to order operations without the program manually waiting and creating the next resource.

A Promise mainly represents eventual completion. An Output additionally carries infrastructure metadata. Ask four questions: what is the eventual value type, is it known during preview, which resources does it depend on, and is it secret? A transformation can change the value while preserving dependency and secrecy.

For example, a database resource’s generated endpoint may be unknown during preview and depend on database. Interpolating https:// creates a new output; it does not erase the database dependency or make the endpoint known earlier. Passing the transformed output into another resource preserves the edge the engine needs.

Avoid extracting an Output into an ordinary variable and pretending synchronous code can use it. Prefer direct Inputs, interpolation helpers, Output.all, or a narrow apply for a transformation that truly needs the resolved value.

Predict known and unknown values during preview

Preview evaluates the program to construct a proposed graph, but values produced only by future provider operations may remain unknown. Pulumi’s apply callback might not run when its input is unknown during preview. Code that creates a resource only inside that callback can therefore hide the resource from the preview.

Compare these shapes:

const db = new Database("db", {});
const app = new Service("app", { endpoint: db.endpoint });

The resource declaration is visible while its input may be unknown. In contrast:

db.endpoint.apply(endpoint => {
  return new Service("app", { endpoint });
});

The second declaration depends on callback execution. Pulumi’s official apply guidance warns that resources created inside callbacks may not appear in preview. That is an observability and correctness concern, not a style preference.

Move the resource outside apply and pass the Output as an Input whenever the constructor accepts it. Use apply to derive a value, not as a general sequencing block. If conditional resource existence truly depends on a provider-generated value, explain the preview limitation and consider whether the condition should be an explicit configuration input instead.

Trace an original dependency example

The local model begins with three values. A plain region is known, non-secret, and has no resource dependency. A database ID is unknown during preview and depends on database. A configured password is known to the program and marked secret.

Combining region with the database ID produces an endpoint that remains unknown and keeps the database dependency. Combining that endpoint with the password produces a DSN that is still unknown, depends on the database, and is secret.

ValueKnown in model preview?DependenciesSecret?
Region literalYesNoneNo
Database IDNodatabaseNo
Derived endpointNodatabaseNo
Endpoint plus passwordNodatabaseYes

Eight local checks passed: plain-known state, provider unknown state, dependency propagation, unknown propagation, secret propagation, retained dependency in the combined DSN, plaintext availability inside a secret callback, and the preview risk of a resource inside an unknown callback. These are model assertions based on documented rules, not SDK execution.

Keep declarations visible during preview

When reviewing a snippet, mark every new Resource expression. If one appears inside apply, ask whether the callback input is known during preview. If not, the preview graph may omit that resource. Then ask whether the constructor property already accepts Input<T>; most Pulumi resource inputs do.

Refactor by declaring the resource at program scope and passing the Output directly. For string construction, use language helpers such as pulumi.interpolate. For multiple values, use pulumi.all and return a transformed value. The returned output preserves dependencies from its inputs.

Do not claim that every apply is wrong. It is appropriate for transformations that require the resolved value. The issue is using runtime callback execution to determine infrastructure graph shape, especially when the preview cannot evaluate it.

Explain what preview can still show: the resource and an unknown property can be visible, which gives reviewers a more complete plan. The exact provider diff may still depend on values that become known only during update.

Follow secret propagation—and its boundary

Official behavior: values read with secret configuration helpers or wrapped with pulumi.secret are marked secret. Combining a secret Output through apply or Output.all marks the resulting Output secret. Pulumi encrypts secret values where they are persisted in state and redacts them in supported displays.

That protection has a critical boundary. The callback passed to apply receives the underlying plaintext value. Pulumi cannot prevent application code from printing it, writing it to a file, sending it over a network, or embedding it in an unprotected external system.

Therefore “Pulumi secrets can never appear in logs” is false. A better answer is: secret marking propagates through supported Output transformations and protects state/display handling, while user code inside callbacks must still avoid disclosure.

Use dummy strings in interview examples. Never paste credentials into prompts, screenshots, test fixtures, or source control. If an output is sensitive even though the provider does not automatically mark it, use additionalSecretOutputs or explicitly wrap it, then verify how the value appears in preview, update output, and exported state.

Diagnose four short code-reading scenarios

Known configuration: A plain environment name drives resource naming. It can be read during preview and does not create a dependency. Validate allowed names before resource construction.

Provider-generated ID: A network ID becomes another resource’s input. Pass the Output directly. The engine sees the dependency even while the preview displays an unknown value.

Resource inside apply: A bucket is created only after a generated suffix resolves. The preview may omit it. Move construction out and pass an interpolated Output name when the provider input supports it.

Secret interpolation: A username and secret password form a connection string. The combined result should remain secret, but a callback that logs the string leaks plaintext. Return the transformed value without logging and limit where it flows.

For each scenario, answer in the same order: graph visibility, known state, dependency set, secret state, and corrective action. This structure prevents vague answers such as “Pulumi waits for it” from hiding the important distinction.

Explain preview, update, and refresh separately

Preview computes proposed operations from program, configuration, and recorded state without applying provider changes. Update performs the operations. Refresh reads actual provider state into Pulumi state; it is not automatically the same as previewing with newly refreshed reality unless the command and flags request that behavior.

If an interviewer reports an unexpected preview, inspect program changes, configuration stack, current state, provider version, unknown values, and whether drift has been refreshed. Do not immediately edit state manually. State editing is an advanced recovery action with a much larger risk surface.

A safe explanation states what was observed and which command produced it. “The resource is absent because it is inside an apply whose input is unknown during preview” is testable. “Pulumi is asynchronous” is too broad to guide a fix.

Use AI without leaking infrastructure context

An AI assistant can help compare transformations or explain a diagnostic, but provide minimal synthetic context. Replace account IDs, endpoints, stack exports, and secrets. Ask the tool to classify known/dependency/secret properties, then verify each conclusion against current Pulumi documentation and the actual type signatures.

Reject suggestions that call console.log inside a secret callback, convert Output values with unsupported hacks, or move resources into apply merely to access a string. Explain why the generated code damages the graph or secrecy boundary.

Work through a review conversation

Suppose a pull request reads a database password with requireSecret, combines it with a generated hostname inside apply, logs the completed DSN for debugging, and creates an application resource in the same callback. Start by acknowledging the correct part: the input is marked secret, and the transformed Output inherits that secret marking.

Then identify two independent problems. Logging happens inside the callback after Pulumi supplies the plaintext secret, so secret marking cannot protect that log. Creating the application in the callback also ties graph construction to whether the hostname is known during preview. The preview may omit the application, giving the reviewer an incomplete proposed plan.

Propose a narrow repair. Remove the log. Create the application outside the callback and pass a secret interpolated Output into its secret-capable input. If the provider does not treat the resulting property as sensitive, explicitly mark the corresponding output or wrap the value according to current SDK guidance. Add a test or policy check that rejects obvious secret logging patterns, while recognizing that static checks cannot prove every runtime sink is safe.

Finally, state what remains to verify in a disposable stack: the preview includes the application with an unknown/redacted property; the update orders the database before the dependent application; CLI output redacts the DSN; and exported state contains encrypted secret material rather than plaintext. Do not display the actual secret while collecting evidence.

This answer is stronger than “use apply for async values” because it separates value transformation, resource declaration, dependency tracking, and disclosure risk. It also gives the reviewer a concrete before/after observation.

Recognize limits of the local model

The eight-check Python model represents three flags and a dependency set. It does not implement Pulumi’s engine, language SDK, provider lifecycle, secret encryption, state backend, or preview renderer. Its value is diagnostic: every transformation must preserve the relevant metadata. The official docs establish actual platform behavior.

For hands-on preparation, create a disposable local or no-cost test stack with obvious fake values, pin Pulumi and provider versions, and save sanitized preview output. Compare a direct Input resource with a resource declared inside an unknown apply. Then combine a marked secret with a plain value and inspect only whether output is redacted—not the secret itself. Destroy the disposable resources afterward according to the provider’s normal workflow.

If you lack a safe provider environment, stop at mocks and code review. Describe that boundary accurately. Mocks can verify program structure and transformation logic, but they do not prove provider diffs, cloud permissions, encryption backend behavior, or recovery from partial updates.

Sources and Further Reading