<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0"><channel><title>Pulumi Blog: Features</title><link>https://www.pulumi.com/blog/tag/features/</link><description>Pulumi blog posts: Features.</description><language>en-us</language><pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate><item><title>Automatic Logging for Faster, Secure Debugging</title><link>https://www.pulumi.com/blog/automatic-logging/</link><pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/automatic-logging/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/automatic-logging/index.png" /&gt;
&lt;p&gt;Pulumi v3.254.0 introduces automatic logging: every operation is logged in an encrypted log file that can optionally be shared with the Pulumi team for inspection. No more re-running commands just to get logs to the Pulumi team for debugging; instead you can share existing logs securely.&lt;/p&gt;
&lt;p&gt;You might have been in a situation where pulumi hit an error for an unexpected reason, or did something that was not quite right. Currently the process for trying to resolve that is to try and reproduce the error, ideally now with logging enabled. Sometimes the error doesn&amp;rsquo;t reproduce, or the state pulumi was in at the time of the error doesn&amp;rsquo;t exist anymore. And even if the issue reproduces it&amp;rsquo;s a bit of a hassle to do all this again, just to get logs to Pulumi employees who can do something with them. There&amp;rsquo;s also no great mechanism to send the potentially sensitive log file.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;From pulumi v3.254.0 onward, we automatically produce log files for every operation and store them in &lt;code&gt;$PULUMI_HOME/logs&lt;/code&gt;. These log files are encrypted on disk, using the relevant stack&amp;rsquo;s secret manager, whenever it is available, as they still contain secrets at this point. The final file consists of gzip&amp;rsquo;d chunks that are encrypted using AES256-GCM. Log files are gzip&amp;rsquo;d when no secrets manager is available, as no secrets from property values can be in the log at that point.&lt;/p&gt;
&lt;p&gt;Note that the logs are rotated out after 7 days, or after the log directory has reached 500 MB, removing the oldest logs first. This way logs will never fill up your disk, but will still be available after running pulumi commands. These defaults can be overridden with the &lt;code&gt;PULUMI_LOG_ROTATION_MAX_AGE_DAYS&lt;/code&gt; and &lt;code&gt;PULUMI_LOG_ROTATION_MAX_TOTAL_MB&lt;/code&gt; environment variables.&lt;/p&gt;
&lt;p&gt;Locally these logs can be decrypted using &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_logs_decrypt/"&gt;&lt;code&gt;pulumi logs decrypt&lt;/code&gt;&lt;/a&gt;. For this to work the same stack&amp;rsquo;s secret manager as was used for the command needs to be available.&lt;/p&gt;
&lt;h2 id="sharing-logs"&gt;Sharing logs&lt;/h2&gt;
&lt;p&gt;Previously there was no good way to securely share the logs with us. Users were always forced to find a way to send the logs to us on their own. With the latest pulumi version, we introduce the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_logs_share/"&gt;&lt;code&gt;pulumi logs share&lt;/code&gt;&lt;/a&gt; command. This will automatically create a key, safely stored on the server side, and re-encrypt the log with that key, redacting all the secrets by default.&lt;/p&gt;
&lt;p&gt;This key can then be accessed by Pulumi employees and Pulumi employees only via an internal tool to decrypt the log. Again we encrypt the log using AES256-GCM. Given this encryption the log can be shared over unsafe channels, and still be secure, even if it&amp;rsquo;s posted on a GitHub issue.&lt;/p&gt;
&lt;p&gt;And while we strive to keep the Pulumi experience as issue free as possible, this should drastically simplify the debugging experience when it is still necessary.&lt;/p&gt;</description><author>Thomas Gummerer</author><category>logging</category><category>observability</category><category>features</category></item><item><title>Discovered Stacks: One Place for All Your Infrastructure</title><link>https://www.pulumi.com/blog/discovered-stacks/</link><pubDate>Thu, 30 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/discovered-stacks/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/discovered-stacks/index.png" /&gt;
&lt;p&gt;Today we&amp;rsquo;re launching &lt;strong&gt;Discovered Stacks&lt;/strong&gt;: Pulumi Cloud now models your AWS CloudFormation stacks and Azure Resource Manager deployments as stacks, right alongside your Pulumi IaC stacks. And when you&amp;rsquo;re ready to bring them under Pulumi management, migration is built in, with every resource tracked until the code provably matches the cloud.&lt;/p&gt;
&lt;h2 id="why-your-infrastructure-doesnt-live-in-one-tool"&gt;Why: your infrastructure doesn&amp;rsquo;t live in one tool&lt;/h2&gt;
&lt;p&gt;Almost nobody&amp;rsquo;s cloud estate is a single technology. There&amp;rsquo;s the CloudFormation that came with the AWS account, the ARM templates from the Azure team, the Terraform from an acquisition, and the Pulumi you&amp;rsquo;re standardizing on. Each tool has its own console, its own grouping, its own idea of state, and no single place shows you everything you run.&lt;/p&gt;
&lt;p&gt;That fragmentation is also why migrations stall. Moving a stack to Pulumi has never been the hard part; &lt;em&gt;knowing where you stand&lt;/em&gt; is. The tracking lives in a spreadsheet, the spreadsheet goes stale the day it&amp;rsquo;s written, and six months later nobody can say which of the 800 resources made it across and which were quietly forgotten.&lt;/p&gt;
&lt;h2 id="nothing-gets-lost"&gt;Nothing gets lost&lt;/h2&gt;
&lt;p&gt;Discovered Stacks gives you confidence that your migration plan or governance efforts will include all resources. This catches a common failure mode where resources are missed by your existing migration scripts or automations. When &lt;a href="https://www.pulumi.com/docs/insights/"&gt;Pulumi Insights&lt;/a&gt; scans your accounts, every CloudFormation stack and ARM deployment becomes a discovered stack, and every resource in it appears as a row with an explicit migration status: ready to migrate, requiring review before migration, or already migrated. Every status is computed from live state on both ends — what Pulumi manages and what the source tool reports — so it&amp;rsquo;s never a stale annotation someone forgot to update.&lt;/p&gt;
&lt;p&gt;Each resource shows its &lt;strong&gt;origin type&lt;/strong&gt; (&lt;code&gt;AWS::S3::Bucket&lt;/code&gt;) next to its &lt;strong&gt;Pulumi type&lt;/strong&gt; (&lt;code&gt;aws:s3/bucket:Bucket&lt;/code&gt;), with the origin properties side by side with Pulumi&amp;rsquo;s view, so you can verify that Pulumi sees exactly what your source tool sees before you change anything. Decisions you make along the way (&lt;em&gt;this resource was deleted, that policy is covered by its parent role&lt;/em&gt;) are recorded by marking the resource resolved: it stays visible to your whole team, deliberately handled rather than quietly forgotten. The spreadsheet is retired.&lt;/p&gt;
&lt;p&gt;&lt;img src="resources-list.png" alt="The Resources grid of a discovered CloudFormation stack in Pulumi Cloud: each row pairs the Pulumi type (aws:sns:Topic) with its origin type (AWS::SNS::Topic), a Managed By column reading CloudFormation, and a provider link out to the resource in the AWS console."&gt;&lt;/p&gt;
&lt;h2 id="migration-on-your-terms"&gt;Migration on your terms&lt;/h2&gt;
&lt;p&gt;When you&amp;rsquo;re ready to migrate, the console is where you plan and build confidence. &lt;strong&gt;Migrate with Neo&lt;/strong&gt; hands the job to &lt;a href="https://www.pulumi.com/docs/ai/"&gt;Pulumi Neo&lt;/a&gt;, which imports the resources, reconciles the generated program, and opens a pull request for review. If you prefer local development, &lt;strong&gt;Generate Import Commands&lt;/strong&gt; gives you the raw materials, and the same API lets your own agents drive the flow.&lt;/p&gt;
&lt;p&gt;Two things hold regardless of the path. Progress is &lt;em&gt;derived&lt;/em&gt;: a resource shows as migrated when it actually exists in the target Pulumi stack, not when someone checks a box. And the quality gate is a &lt;strong&gt;zero-diff &lt;code&gt;pulumi preview&lt;/code&gt;&lt;/strong&gt; — the migration is done when the code demonstrably matches your cloud.&lt;/p&gt;
&lt;p&gt;Terraform stacks whose state you &lt;a href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/"&gt;store in Pulumi Cloud&lt;/a&gt; get the same treatment through a new &lt;strong&gt;Migration&lt;/strong&gt; tab, with statuses derived from the Terraform state.&lt;/p&gt;
&lt;h2 id="try-it"&gt;Try it&lt;/h2&gt;
&lt;p&gt;Open the &lt;strong&gt;Stacks&lt;/strong&gt; page in &lt;a href="https://app.pulumi.com/"&gt;Pulumi Cloud&lt;/a&gt;, turn on &lt;strong&gt;Show Discovered Stacks&lt;/strong&gt;, and your CloudFormation and ARM estates appear next to your IaC. From there:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read the &lt;a href="https://www.pulumi.com/docs/insights/discovery/discovered-stacks/"&gt;Discovered Stacks documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Follow the &lt;a href="https://www.pulumi.com/blog/discovered-stacks-migrate-cloudformation-to-pulumi/"&gt;step-by-step migration tutorial&lt;/a&gt; to take a CloudFormation stack all the way to Pulumi.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;rsquo;d love to hear how it works on your estate — reach out through &lt;a href="https://github.com/pulumi/pulumi-cloud-requests"&gt;Pulumi feedback&lt;/a&gt; or your customer success team.&lt;/p&gt;</description><author>Alejandro Cotroneo</author><category>features</category><category>insights</category><category>pulumi-cloud</category></item><item><title>Enforce Access Token Expiry Policies in Pulumi Cloud</title><link>https://www.pulumi.com/blog/access-token-expiry-policy/</link><pubDate>Mon, 27 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/access-token-expiry-policy/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/access-token-expiry-policy/index.png" /&gt;
&lt;p&gt;Pulumi Cloud organizations can now enforce a maximum expiry on the access tokens used against them. Organization admins can set a cap in days, and from that point on, personal, organization, and team tokens operating on resources in the org must carry an expiration within the cap for requests to succeed. Tokens that never expire, or that have too much lifetime remaining, get rejected with an error that tells the user exactly how to regain access.&lt;/p&gt;
&lt;h2 id="why-cap-token-lifetimes"&gt;Why cap token lifetimes&lt;/h2&gt;
&lt;p&gt;Many organizations already have a credential rotation policy that says tokens must expire, but until now, Pulumi Cloud could only &lt;em&gt;recommend&lt;/em&gt; an expiry at creation time. Nothing stopped a member from creating a never-expiring personal token, and nothing aged out the long-lived tokens created before your policy existed.&lt;/p&gt;
&lt;p&gt;That gap matters because a leaked token is only as dangerous as its remaining lifetime. A token that never expires is a standing liability.&lt;/p&gt;
&lt;p&gt;By adding support for access token expiry policies, Pulumi Cloud now closes the gap at the platform level. Once you&amp;rsquo;ve set the cap, Pulumi Cloud enforces it immediately for your organization, including for tokens that already exist.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;In your organization&amp;rsquo;s settings, navigate to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Access Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Other&lt;/strong&gt; and scroll to &lt;strong&gt;Access token expiry policy&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/access-token-expiry-policy/expiry-policy-card.png" alt="The access token expiry policy card in Pulumi Cloud organization settings, with a 14-day maximum entered and buttons to preview affected tokens and save the policy."&gt;&lt;/p&gt;
&lt;p&gt;You can also get there from the &lt;strong&gt;Access Tokens&lt;/strong&gt; tab, where a banner shows whether a policy is in effect — select &lt;strong&gt;Edit policy&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/access-token-expiry-policy/expiry-policy-banner.png" alt="The banner on the Access Tokens tab stating that the organization caps access token expiry at 14 days, with an Edit policy link."&gt;&lt;/p&gt;
&lt;p&gt;The policy is a single number: the maximum expiry, in days, for tokens used against your organization. Compliance is checked on every request, and a token complies when both of these are true:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It has an expiration date. Never-expiring tokens violate any policy.&lt;/li&gt;
&lt;li&gt;Its &lt;em&gt;remaining lifetime&lt;/em&gt; — the time between now and its expiration — is within the cap.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because compliance is based on remaining lifetime rather than the expiry chosen at creation, the policy is pragmatic about existing credentials: a token created a year ago with a two-year expiry becomes compliant once it has less than the cap remaining. You&amp;rsquo;re enforcing exposure going forward, not retroactively punishing old tokens that are already near the end of their life.&lt;/p&gt;
&lt;p&gt;Enforcement is tailored to each token type:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Organization and team tokens&lt;/strong&gt; can&amp;rsquo;t be created out of compliance: the creation dialog caps the expiry picker at your policy maximum, and the API rejects requests that exceed it. Existing machine tokens that violate the policy stop authenticating and need to be recreated with a compliant expiry.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Personal tokens&lt;/strong&gt; span all of a user&amp;rsquo;s organizations, so they can&amp;rsquo;t be blocked at creation. Instead, a non-compliant personal token is rejected when it&amp;rsquo;s used against your organization, and the member sees an error explaining the policy and how to fix it. The personal token creation dialog also warns members when a chosen expiry doesn&amp;rsquo;t meet a policy in one of their organizations, steering them toward a compliant choice up front.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web console sessions are unaffected&lt;/strong&gt;, as are the short-lived tokens issued through &lt;a href="https://www.pulumi.com/docs/administration/access-identity/oidc-issuers/"&gt;OIDC token exchange&lt;/a&gt; — those are already bounded by their issuer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once a policy is active, the creation dialog does the steering for you — the expiry picker tops out at the policy maximum:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/access-token-expiry-policy/new-token-dialog-capped.png" alt="The New Access Token dialog with the expiration picker set to &amp;ldquo;14 Days (org policy max)&amp;rdquo; and helper text noting the 14-day policy maximum."&gt;&lt;/p&gt;
&lt;h2 id="rolling-it-out-without-breaking-ci"&gt;Rolling it out without breaking CI&lt;/h2&gt;
&lt;p&gt;The riskiest moment for any new enforcement policy is the moment you turn it on. Two things make that safe here.&lt;/p&gt;
&lt;p&gt;First, &lt;strong&gt;Preview affected tokens&lt;/strong&gt; shows you the blast radius before you save: the organization and team tokens that would stop authenticating under the proposed cap, by name and creator. Recreate those credentials with compliant expiries first, then save the policy.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/access-token-expiry-policy/preview-affected-tokens.png" alt="The preview listing one machine token that would fail to authenticate under a 14-day policy, with a note that non-compliant personal tokens are rejected at request time."&gt;&lt;/p&gt;
&lt;p&gt;Second, rejections are designed to be self-explanatory. A blocked request fails with a &lt;code&gt;403 Forbidden&lt;/code&gt; that names your organization and its policy maximum, so a member whose personal token no longer complies knows immediately what happened and what to do: generate a new token that meets the policy. Policy changes are also recorded in your organization&amp;rsquo;s &lt;a href="https://www.pulumi.com/docs/administration/security-compliance/audit-logs/"&gt;audit logs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/access-token-expiry-policy/policy-rejection-cli.png" alt="A pulumi up run rejected with a 403 error stating that the acme-corp organization enforces a max access token expiry of 14 days that the current token does not meet."&gt;&lt;/p&gt;
&lt;p&gt;A reasonable rollout looks like:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Decide on a cap that matches your rotation policy. 90 days is a common choice for CI credentials.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Preview affected tokens&lt;/strong&gt; and recreate any non-compliant machine tokens.&lt;/li&gt;
&lt;li&gt;Socialize the change in your organization: personal tokens without a compliant expiry will stop working against the organization.&lt;/li&gt;
&lt;li&gt;Save the policy. From here on, the platform enforces it for you.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;The access token expiry policy is available now in your organization&amp;rsquo;s access settings. For the full reference — compliance rules, per-token-type behavior, and exemptions — see the &lt;a href="https://www.pulumi.com/docs/administration/access-identity/access-tokens/#access-token-expiry-policy"&gt;access tokens documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have feedback, we&amp;rsquo;d love to hear it in the &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; or on &lt;a href="https://github.com/pulumi/pulumi/issues"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</description><author>Devon Grove</author><category>features</category><category>security</category></item><item><title>Preview ESC Changes with Environment Overrides</title><link>https://www.pulumi.com/blog/preview-esc-environment-changes-with-draft-references/</link><pubDate>Thu, 23 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/preview-esc-environment-changes-with-draft-references/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/preview-esc-environment-changes-with-draft-references/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; makes it easy to store configuration and secrets for your Pulumi programs, and with &lt;a href="https://www.pulumi.com/docs/esc/concepts/approvals/"&gt;Approvals for ESC&lt;/a&gt; you can review and approve changes before they go live. The new &lt;code&gt;--override-env&lt;/code&gt; flag lets you preview any environment change, including an unapproved draft, to see exactly how it would affect your stack before it becomes the latest version.&lt;/p&gt;
&lt;h2 id="example-scenario"&gt;Example scenario&lt;/h2&gt;
&lt;p&gt;Your team stores production app configuration in ESC and has enabled &lt;a href="https://www.pulumi.com/docs/esc/concepts/approvals/"&gt;Approvals&lt;/a&gt; to keep bad values out of critical infrastructure. But one important question remains: how can reviewers properly validate a configuration change before approving it?&lt;/p&gt;
&lt;h2 id="introducing-draft-references-and-the-override-env-flag"&gt;Introducing: draft references and the &amp;ndash;override-env flag&lt;/h2&gt;
&lt;p&gt;We are introducing a new &lt;code&gt;--override-env&lt;/code&gt; flag to the Pulumi CLI that works with every Pulumi operation that can consume ESC environments: &lt;code&gt;preview&lt;/code&gt;, &lt;code&gt;up&lt;/code&gt;, &lt;code&gt;refresh&lt;/code&gt;, and &lt;code&gt;destroy&lt;/code&gt;. This makes it easy to test configuration changes on the fly, giving your team the confidence to validate them as part of the review process.&lt;/p&gt;
&lt;h3 id="example-usages"&gt;Example usages&lt;/h3&gt;
&lt;p&gt;The basic usage is &lt;code&gt;--override-env &amp;lt;env&amp;gt;=&amp;lt;replacement&amp;gt;&lt;/code&gt;, and you can override multiple environments at once!
In this example, we are running a &lt;code&gt;pulumi preview&lt;/code&gt; with environments &lt;code&gt;app/myenv&lt;/code&gt; and &lt;code&gt;app/myenv2&lt;/code&gt; replaced by their draft versions (denoted by &lt;code&gt;@draft:&amp;lt;draft-id&amp;gt;&lt;/code&gt;).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pulumi preview \
--override-env &amp;#34;app/myenv=app/myenv@draft:123e4567-e89b-12d3-a456-426614174000&amp;#34; \
--override-env &amp;#34;app/myenv2=app/myenv2@draft:123e4567-e89b-12d3-a456-426614174000&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;--override-env&lt;/code&gt; flag not only works with draft references, but for any environment too! Here is an example of deploying your stack with your AWS test environment:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pulumi up --override-env &amp;#34;aws-login/prod=aws-login/testing&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note: &lt;code&gt;--override-env&lt;/code&gt; can also override environments that are imported (directly or indirectly) from the ESC environment in your stack config. This allows you to override any environment in the import chain for full flexibility.&lt;/p&gt;
&lt;h2 id="ways-to-use-it"&gt;Ways to use it&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Validate a draft ESC environment with your stack before approving&lt;/li&gt;
&lt;li&gt;One-off debugging without editing stack config&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Draft references and &lt;code&gt;--override-env&lt;/code&gt; are available today in the Pulumi CLI. Upgrade to the &lt;a href="https://www.pulumi.com/docs/install/"&gt;latest release&lt;/a&gt; and try it out! To learn more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/concepts/approvals/"&gt;Approvals for ESC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/get-started/"&gt;Get started with Pulumi ESC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Sean Yeh</author><category>esc</category><category>features</category><category>configuration-management</category></item><item><title>The Standalone ESC CLI Retired: Use pulumi env</title><link>https://www.pulumi.com/blog/esc-cli-retiring-use-pulumi-env/</link><pubDate>Wed, 22 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/esc-cli-retiring-use-pulumi-env/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/esc-cli-retiring-use-pulumi-env/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; CLI v0.26.0 is the latest standalone release. We encourage users to use the &lt;a href="https://www.pulumi.com/docs/iac/cli/"&gt;Pulumi CLI&lt;/a&gt; instead.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/pulumi/esc"&gt;ESC repository&lt;/a&gt; has been archived and the code now lives under &lt;a href="https://github.com/pulumi/pulumi"&gt;pulumi&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="why-are-we-making-this-change"&gt;Why are we making this change&lt;/h2&gt;
&lt;p&gt;Pulumi ESC is the best way to store and manage configuration and secrets in your Pulumi programs and while you can certainly use ESC to store secrets and configurations for your applications or to manage your AI agents&amp;rsquo; credentials, it&amp;rsquo;s still a core feature of &lt;a href="https://www.pulumi.com/docs/iac/guides/basics/pulumi-cloud-vs-oss/"&gt;Pulumi Cloud&lt;/a&gt;, and we want to make sure we deliver a consistent experience across our entire suite.&lt;/p&gt;
&lt;p&gt;In addition to consistency, ESC and the Pulumi CLI share a lot of capabilities to interface to Pulumi Cloud and we want to make it easier and simpler for our customers: it&amp;rsquo;s now easier to understand which Pulumi organization you are working with, which user is logged in, etc.&lt;/p&gt;
&lt;h3 id="playing-nicer-with-humans-and-ai-agents"&gt;Playing nicer with humans and AI agents&lt;/h3&gt;
&lt;p&gt;A single CLI means one binary to install, one login to manage, and one place to look things up. This simplicity is beneficial whether the operator is a person or an agent.&lt;/p&gt;
&lt;p&gt;AI agents love code, and they love CLIs. By unifying the Pulumi CLI and ESC we offer a single place to look up operations around your Pulumi programs. Agents can now reason better about where to store configuration and secrets, without being confused by multiple CLI options that interface against the same service.&lt;/p&gt;
&lt;h3 id="faster-improvements"&gt;Faster improvements&lt;/h3&gt;
&lt;p&gt;With a shared CLI, any improvement to account management is automatically delivered to both: Pulumi and ESC users. At the same time, both benefit from ESC improvements and new features from day 1.&lt;/p&gt;
&lt;p&gt;ESC is a core component of our platform; a separate interface no longer makes sense.&lt;/p&gt;
&lt;h3 id="the-same-code-all-along"&gt;The same code all along&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re wondering what actually changes under the hood: nothing about how the commands work. The &lt;code&gt;pulumi env&lt;/code&gt; commands were never a reimplementation — the Pulumi CLI has built them from the ESC CLI&amp;rsquo;s own code since ESC&amp;rsquo;s first release, which is why the same command surface has always been available under &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_env/"&gt;&lt;code&gt;pulumi env&lt;/code&gt;&lt;/a&gt;. What we&amp;rsquo;re retiring is a second way to ship and install that code, not the code itself.&lt;/p&gt;
&lt;h2 id="do-i-need-to-update"&gt;Do I need to update?&lt;/h2&gt;
&lt;p&gt;If you are using the ESC CLI, you should switch as soon as possible, as the standalone binary will not get the latest features. Don&amp;rsquo;t worry — the mapping is mechanical, and the &lt;a href="https://www.pulumi.com/docs/esc/guides/migrate-from-esc-cli/"&gt;migration guide&lt;/a&gt; covers it command by command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;esc env &amp;lt;command&amp;gt;&lt;/code&gt; becomes &lt;code&gt;pulumi env &amp;lt;command&amp;gt;&lt;/code&gt;. For example, &lt;code&gt;esc env ls&lt;/code&gt; becomes &lt;code&gt;pulumi env ls&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;esc open&lt;/code&gt; and &lt;code&gt;esc run&lt;/code&gt; shortcuts become &lt;code&gt;pulumi env open&lt;/code&gt; and &lt;code&gt;pulumi env run&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;esc login&lt;/code&gt;, &lt;code&gt;esc logout&lt;/code&gt;, and &lt;code&gt;esc version&lt;/code&gt; become &lt;code&gt;pulumi login&lt;/code&gt;, &lt;code&gt;pulumi logout&lt;/code&gt;, and &lt;code&gt;pulumi version&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are already using the Pulumi CLI, you have nothing to worry about; this has no effect since ESC commands were already available under the &lt;code&gt;pulumi env&lt;/code&gt; sub-command.&lt;/p&gt;
&lt;p&gt;Ready to switch? &lt;a href="https://www.pulumi.com/docs/install/"&gt;Install the Pulumi CLI&lt;/a&gt; if you don&amp;rsquo;t have it yet, then run &lt;code&gt;pulumi env ls&lt;/code&gt; to see your environments. Every command is documented in the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_env/"&gt;&lt;code&gt;pulumi env&lt;/code&gt; reference&lt;/a&gt;.&lt;/p&gt;</description><author>Pablo Terradillos</author><author>Boris Schlosser</author><category>esc</category><category>features</category></item><item><title>Introducing Usage Limits for Pulumi Neo</title><link>https://www.pulumi.com/blog/neo-usage-limits/</link><pubDate>Tue, 14 Jul 2026 08:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/neo-usage-limits/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-usage-limits/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/ai/"&gt;Pulumi Neo&lt;/a&gt; is an AI agent that takes on real infrastructure work, and it&amp;rsquo;s natural to want to hand it more and more. Usage limits give you control so you can do exactly that: set a monthly dollar limit, and Neo pauses when your organization reaches it.&lt;/p&gt;
&lt;h2 id="how-usage-limits-work"&gt;How usage limits work&lt;/h2&gt;
&lt;p&gt;Your organization limit is a single monthly dollar amount covering all Neo usage across the org. To set one:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the Pulumi Cloud console, navigate to &lt;strong&gt;Settings → Billing &amp;amp; usage → Neo token usage&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Manage token usage&lt;/strong&gt; panel, enter an organization limit.&lt;/li&gt;
&lt;li&gt;Save your changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When usage reaches the limit, Neo pauses for the rest of the billing period and resumes automatically at the start of the next one. An Admin or Billing Manager can raise the limit to resume before then.&lt;/p&gt;
&lt;p&gt;&lt;img src="manage-token-usage.png" alt="The Manage token usage panel, where an admin sets the organization&amp;rsquo;s monthly Neo limit and turns on email notifications."&gt;&lt;/p&gt;
&lt;p&gt;Enforcement happens at a natural boundary in Neo&amp;rsquo;s work, so a task already in progress finishes its current step before pausing. As a result, usage can go a few dollars over the set limit.&lt;/p&gt;
&lt;h2 id="per-member-limits-and-alerts"&gt;Per-member limits and alerts&lt;/h2&gt;
&lt;p&gt;You can also set a separate limit for each member. A member is paused at whichever limit is smaller: their own or the organization&amp;rsquo;s. For example, a member with a $200 limit under a $150 organization limit pauses at $150, because the organization limit is smaller.&lt;/p&gt;
&lt;p&gt;&lt;img src="per-member-limits.png" alt="The per-member limits table, showing each member&amp;rsquo;s amount used and effective limit for the billing period."&gt;&lt;/p&gt;
&lt;p&gt;Turn on &lt;strong&gt;Enable email notifications&lt;/strong&gt; to get a heads-up before you reach the limit. Billing admins are alerted at 50%, 80%, and 95% of the organization limit, with a final notice at 100% when Neo pauses.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Set your usage limits and stay in control as your organization hands Neo more and more work. Usage limits are available today for organizations on a paid plan, and an &lt;strong&gt;Admin&lt;/strong&gt; or &lt;strong&gt;Billing Manager&lt;/strong&gt; can set them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://app.pulumi.com/signin"&gt;Sign in to Pulumi Cloud&lt;/a&gt; and set your first organization limit&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/ai/usage-limits/"&gt;Read the Neo usage limits documentation&lt;/a&gt; for per-member limits, alerts, and enforcement details&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slack.pulumi.com/"&gt;Join the Community Slack&lt;/a&gt; to share your feedback&lt;/li&gt;
&lt;/ul&gt;</description><author>John Keiser</author><category>pulumi-neo</category><category>ai</category><category>ai-agents</category><category>features</category></item><item><title>Sign in to Pulumi Cloud with Passkeys</title><link>https://www.pulumi.com/blog/passkey-support-in-pulumi-cloud/</link><pubDate>Mon, 13 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/passkey-support-in-pulumi-cloud/</guid><description>
&lt;img src="https://www.pulumi.com/blog/passkey-support-in-pulumi-cloud/meta.png" /&gt;
&lt;p&gt;Pulumi Cloud now supports passkeys for users who sign in with email and password. Select a button, approve with Touch ID, Face ID, Windows Hello, or your hardware key, and you&amp;rsquo;re signed in.&lt;/p&gt;
&lt;p&gt;A passkey is a public-key credential stored on your device: your phone, your laptop, a hardware key (YubiKey, Google Titan, etc.), or your password manager can all function as the authenticator. When you sign in, your device authenticates you locally and signs a challenge from Pulumi Cloud with the private key.&lt;/p&gt;
&lt;p&gt;The private key stays on your device — Pulumi Cloud never sees or stores it. Passkeys are built on the &lt;a href="https://www.w3.org/TR/webauthn-3/"&gt;WebAuthn&lt;/a&gt; standard, so they&amp;rsquo;re already supported on every major browser and operating system.&lt;/p&gt;
&lt;h2 id="who-this-is-for"&gt;Who this is for&lt;/h2&gt;
&lt;p&gt;This release applies to users who sign in to Pulumi Cloud with an email address and password. If you sign in through an identity provider (IdP), such as GitHub OAuth, GitLab, Bitbucket, Google, or your organization&amp;rsquo;s SAML SSO, your existing flow is unchanged.&lt;/p&gt;
&lt;h2 id="why-passkeys"&gt;Why passkeys&lt;/h2&gt;
&lt;p&gt;Passwords have always been the weakest link in account security. Since they are shared secrets, they are vulnerable to phishing attacks, and every place you type one is a place that can be impersonated or a data store that can be leaked. Passkeys swap that out for a per-site key pair that lives on your device:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phishing-resistant by design.&lt;/strong&gt; A passkey is bound to the exact origin it was registered for. A look-alike domain can&amp;rsquo;t trigger your authenticator.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Synced across your devices.&lt;/strong&gt; Apple iCloud Keychain, Google Password Manager, 1Password, Dashlane, Bitwarden: most credential managers now sync passkeys end-to-end-encrypted to every device you&amp;rsquo;ve signed in on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discoverable.&lt;/strong&gt; Pulumi Cloud doesn&amp;rsquo;t need to know which user you are before you authenticate. Just select &amp;ldquo;Sign in with a passkey&amp;rdquo; and your device offers the right credential.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nothing to remember.&lt;/strong&gt; A passkey lives on your device. There&amp;rsquo;s no string to memorize, and no sensitive credential stored by us.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="setting-up-a-passkey"&gt;Setting up a passkey&lt;/h2&gt;
&lt;p&gt;The next time you sign in with a password, Pulumi Cloud will ask if you&amp;rsquo;d like to configure a passkey. It&amp;rsquo;s a single-step prompt, so you can enroll once and take advantage of passkeys on every subsequent sign-in.&lt;/p&gt;
&lt;p&gt;If you dismiss the prompt and would like to add one later, or want to add multiple passkeys, navigate to &lt;strong&gt;Account Settings → Passkeys&lt;/strong&gt; under your user profile. Select &lt;strong&gt;Register a passkey&lt;/strong&gt;, complete the OS-level prompt (Touch ID, Face ID, Windows Hello, or your hardware key), and you&amp;rsquo;re done. Pulumi Cloud will pick a sensible default name like &lt;code&gt;&amp;quot;iCloud Keychain&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;Chrome on macOS&amp;quot;&lt;/code&gt; based on the authenticator, but you can rename it inline anytime under &lt;strong&gt;Account Settings → Passkeys&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/passkey-support-in-pulumi-cloud/account-settings-passkeys.png" alt="Pulumi Cloud Account Settings page showing the Passkeys section, with a &amp;ldquo;Register a passkey&amp;rdquo; button and an enrolled passkey named &amp;ldquo;Pulumipus&amp;rsquo;s iPhone&amp;rdquo;."&gt;&lt;/p&gt;
&lt;p&gt;You can register as many passkeys as you want. Typical setups are one per personal device, or one synced credential plus a hardware key as backup. Removing a passkey takes effect immediately; deleted credentials cannot be used to sign in.&lt;/p&gt;
&lt;h2 id="signing-in"&gt;Signing in&lt;/h2&gt;
&lt;p&gt;Depending on how you arrive:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Explicit sign-in.&lt;/strong&gt; On the sign-in page, select &lt;strong&gt;Sign in with a passkey&lt;/strong&gt;. Your browser opens the passkey picker, and you authenticate from there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autofill.&lt;/strong&gt; If your browser supports &lt;a href="https://web.dev/articles/passkey-form-autofill"&gt;conditional mediation&lt;/a&gt; (Chrome, Safari, Edge, recent Firefox), the email field on the sign-in page proactively offers your registered passkeys as autofill suggestions. Pick one and you&amp;rsquo;re signed in.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-about-my-existing-password-and-mfa"&gt;What about my existing password and MFA?&lt;/h2&gt;
&lt;p&gt;Your existing password still works. Passkeys are an additional sign-in option, not a replacement, and they don&amp;rsquo;t disable password sign-in on your account. If you lose access to every registered passkey, you can still sign in with your email and password as you always have, then register a new passkey from settings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Other 2FA still applies.&lt;/strong&gt; If you have TOTP-based MFA enabled on your Pulumi account, a passkey sign-in will still prompt for your second factor. WebAuthn doesn&amp;rsquo;t reliably tell us &lt;em&gt;how&lt;/em&gt; you unlocked the passkey on your device (biometric, PIN, or something weaker), so we can&amp;rsquo;t safely treat the passkey itself as proof of two factors. Your existing MFA configuration remains the boundary it always was.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Passkey support is generally available today for every Pulumi Cloud user who signs in with email and password, at no additional cost and with no configuration. Visit &lt;a href="https://app.pulumi.com/account/profile"&gt;your account settings&lt;/a&gt; to register your first passkey, and let us know what you think on &lt;a href="https://slack.pulumi.com/"&gt;our community Slack&lt;/a&gt; or &lt;a href="https://github.com/pulumi/pulumi/issues"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</description><author>Devon Grove</author><category>features</category><category>security</category><category>product-launches</category></item><item><title>New: Versioned CLI and SDK Docs</title><link>https://www.pulumi.com/blog/previous-cli-and-sdk-version-docs/</link><pubDate>Tue, 07 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/previous-cli-and-sdk-version-docs/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/previous-cli-and-sdk-version-docs/index.png" /&gt;
&lt;p&gt;Pinned to an older Pulumi CLI or SDK version and finding that the docs describe a newer release? The &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/"&gt;Pulumi CLI command reference&lt;/a&gt; and the SDK API docs now include a version selector, so the documentation you&amp;rsquo;re reading matches the version you&amp;rsquo;re actually running.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;When you open the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/"&gt;CLI command reference&lt;/a&gt;, you&amp;rsquo;ll see a version dropdown near the top of the page, below the title. The SDK API docs carry the same dropdown in the upper-right corner. Choose a release, and the page loads the documentation generated for that exact version.&lt;/p&gt;
&lt;p&gt;&lt;img src="cli-version-selector.png" alt="Version selector near the top of the Pulumi CLI command reference"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="sdk-version-selector.png" alt="Version selector in the upper-right corner of the Pulumi Node.js SDK API docs"&gt;&lt;/p&gt;
&lt;h2 id="whats-available"&gt;What&amp;rsquo;s available&lt;/h2&gt;
&lt;p&gt;Alongside the latest release, we keep immutable snapshots of previous versions going back to v3.150.0 (early 2025). The CLI command reference and the Node.js, Python, .NET, and Java SDK API docs are all covered, so the docs you need are only a dropdown away. (The Go SDK is versioned on &lt;a href="https://pkg.go.dev/github.com/pulumi/pulumi/sdk/v3"&gt;pkg.go.dev&lt;/a&gt;, so its documentation lives there rather than in the Pulumi docs.)&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Head to the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/"&gt;CLI command reference&lt;/a&gt; or the &lt;a href="https://www.pulumi.com/docs/reference/"&gt;SDK API docs&lt;/a&gt; and try the version dropdown. Selections are sticky, so when you navigate into a version, you&amp;rsquo;ll be able to click around within that same version without having to choose it again.&lt;/p&gt;
&lt;p&gt;Have feedback? Let us know in the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt; or by opening an issue on &lt;a href="https://github.com/pulumi/docs"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/docs/iac/cli/commands/"
class="btn btn-primary"
&gt;
Browse the CLI command reference
&lt;/a&gt;</description><author>Cam Soper</author><category>pulumi-cli</category><category>features</category><category>announcements</category></item><item><title>Enforce ISO 27001 Across Your AWS Infrastructure</title><link>https://www.pulumi.com/blog/iso-27001-policy-pack-for-aws/</link><pubDate>Tue, 30 Jun 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/iso-27001-policy-pack-for-aws/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/iso-27001-policy-pack-for-aws/index.png" /&gt;
&lt;p&gt;ISO/IEC 27001 is the international standard for information security management. Proving you meet it usually means months of mapping abstract security controls to concrete cloud configuration, then authoring custom checks one resource at a time. We&amp;rsquo;re changing that.&lt;/p&gt;
&lt;p&gt;Today we&amp;rsquo;re shipping a pre-built ISO/IEC 27001:2022 policy pack for AWS, live now in Pulumi Cloud as &lt;code&gt;iso-27001-aws&lt;/code&gt;. It encodes the standard&amp;rsquo;s security expectations as 238 ready-to-run policies, so you can align your AWS estate to ISO 27001 in minutes, not months.&lt;/p&gt;
&lt;h2 id="why-iso-27001-matters"&gt;Why ISO 27001 matters&lt;/h2&gt;
&lt;p&gt;For many companies, ISO 27001 is what stands between them and a customer or a market. The sooner you can reach a certifiable state and prove you stay there, the less compliance slows the business down. The pack collapses months of policy work into something you run continuously, so security keeps pace with growth instead of blocking it.&lt;/p&gt;
&lt;h2 id="how-the-pack-maps-to-iso-27001"&gt;How the pack maps to ISO 27001&lt;/h2&gt;
&lt;p&gt;The hard part of ISO 27001 has always been translation: its controls are written in the language of governance and risk management, not in the language of AWS resources. Every team has had to interpret each control and decide what it means for an S3 bucket or an RDS instance.&lt;/p&gt;
&lt;p&gt;The pack does that interpretation for you. Its 238 policies are aligned to the relevant ISO 27001 controls, so each result connects back to the standard instead of leaving you to map it yourself. You can browse the full pack in the &lt;a href="https://www.pulumi.com/docs/reference/pre-built-policy-packs/iso-27001/aws/"&gt;pack reference&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="audit-and-prevent"&gt;Audit and prevent&lt;/h2&gt;
&lt;p&gt;The same pack works two ways, so you can both reach compliance and stay there:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Audit.&lt;/strong&gt; Scan your existing AWS estate against the pack, including resources that Pulumi doesn&amp;rsquo;t manage. You get an honest baseline of where you stand against ISO 27001 today, with every finding tied back to the control it affects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prevent.&lt;/strong&gt; Run the same pack as a preventative policy during &lt;code&gt;pulumi up&lt;/code&gt; to block non-compliant resources before they&amp;rsquo;re ever created. New infrastructure is born aligned to the standard.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Audit gets you clean. Preventative policies keep you clean.&lt;/p&gt;
&lt;h2 id="a-growing-library-of-pre-built-packs"&gt;A growing library of pre-built packs&lt;/h2&gt;
&lt;p&gt;ISO 27001 joins a growing library of pre-built packs for AWS, each authored and maintained by Pulumi and kept current with its source standard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ISO/IEC 27001:2022&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CIS Controls v8.1&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NIST SP 800-53 Rev. 5&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PCI DSS v4.0&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HITRUST CSF v11.5&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pulumi Best Practices&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adopting any pack means you skip the authoring work entirely, inherit framework mappings maintained by Pulumi, and apply a consistent baseline across every stack and account.&lt;/p&gt;
&lt;h2 id="get-started-today"&gt;Get started today&lt;/h2&gt;
&lt;p&gt;The ISO 27001 pack is available now to every Pulumi Cloud user:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Browse the &lt;a href="https://www.pulumi.com/docs/reference/pre-built-policy-packs/iso-27001/aws/"&gt;pack reference&lt;/a&gt; to see all 238 policies and how they map to the standard&amp;rsquo;s controls.&lt;/li&gt;
&lt;li&gt;Explore the full &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-packs/pre-built-packs/"&gt;pre-built packs index&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Follow the &lt;a href="https://www.pulumi.com/docs/insights/policy/get-started/"&gt;get-started guide&lt;/a&gt; to run your first audit.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="try-pulumi-policies"&gt;Try Pulumi policies&lt;/h2&gt;
&lt;p&gt;Ready to align your AWS infrastructure to ISO 27001? &lt;a href="https://app.pulumi.com/signup"&gt;Sign up for Pulumi Cloud&lt;/a&gt; and run the pack against your estate, or read the &lt;a href="https://www.pulumi.com/docs/insights/policy/get-started/"&gt;policy get-started guide&lt;/a&gt; to dig in.&lt;/p&gt;
&lt;p&gt;Need a compliance pack for a framework that isn&amp;rsquo;t listed here? Open a request in &lt;a href="https://github.com/pulumi/pulumi-cloud-requests"&gt;pulumi/pulumi-cloud-requests&lt;/a&gt; or come tell us in the &lt;a href="https://slack.pulumi.com/"&gt;community Slack&lt;/a&gt;. We&amp;rsquo;re listening.&lt;/p&gt;</description><author>Dan Biwer</author><category>pulumi-cloud</category><category>policy-as-code</category><category>crossguard</category><category>features</category><category>compliance</category><category>governance</category><category>security</category></item><item><title>Neo code reviews: AI code review built for infrastructure</title><link>https://www.pulumi.com/blog/neo-code-reviews/</link><pubDate>Mon, 22 Jun 2026 08:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/neo-code-reviews/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-code-reviews/index.png" /&gt;
&lt;p&gt;Today we&amp;rsquo;re introducing &lt;a href="https://www.pulumi.com/docs/ai/code-reviews/"&gt;Pulumi Neo code reviews&lt;/a&gt;, now in public preview. Neo code reviews analyze pull request changes in conjunction with what Pulumi Cloud knows about your running infrastructure, providing both high-level and code-level feedback.&lt;/p&gt;
&lt;p&gt;Normal code review agents can&amp;rsquo;t reliably anticipate the impact an infrastructure-as-code change will have. This is because they don&amp;rsquo;t have access to critical aspects of the IaC workflow: the potential impact the update will have, in this case the &lt;code&gt;pulumi preview&lt;/code&gt; output; and the current state of the cloud infrastructure. Neo not only has access to both of those, but also to the entirety of your other cloud context, such as stack relationships and dependencies.&lt;/p&gt;
&lt;h2 id="running-reviews"&gt;Running reviews&lt;/h2&gt;
&lt;p&gt;Neo can review every pull request automatically, or only when someone mentions &lt;code&gt;@pulumi-neo&lt;/code&gt;. Either way, it skips draft pull requests and those opened by bots by default.&lt;/p&gt;
&lt;p&gt;A review is a comment, so it informs the person approving the merge and sits alongside the required checks and branch protection you already enforce. Neo code reviews run inside the same governance as every other Neo task, with the &lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/"&gt;RBAC&lt;/a&gt;, guardrails, and audit logging your organization has set.&lt;/p&gt;
&lt;p&gt;&lt;img src="neo-code-review.png" alt="Neo code review on a GitHub pull request, showing a risk assessment and the resource changes the update would make"&gt;&lt;/p&gt;
&lt;h2 id="enable-code-reviews"&gt;Enable code reviews&lt;/h2&gt;
&lt;p&gt;Neo code reviews are available on GitHub during public preview. They require Pulumi Neo to be enabled for your organization, the &lt;a href="https://www.pulumi.com/docs/integrations/version-control/github-app/"&gt;Pulumi GitHub App&lt;/a&gt; installed on the repositories you want reviewed, and a one-time grant from each organization user to access their GitHub account under &lt;strong&gt;Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Version control&lt;/strong&gt;. If Neo currently posts preview summaries on your pull requests, code reviews are already enabled, and they take the place of those summaries.&lt;/p&gt;
&lt;p&gt;Neo code reviews are free while in public preview. On July 1, 2026, they&amp;rsquo;ll be generally available, and reviews will begin counting toward your organization&amp;rsquo;s Neo token usage, at the same per-token rate as any other Neo task. The &lt;a href="https://www.pulumi.com/pricing/"&gt;pricing page&lt;/a&gt; shows that rate and the monthly token allotment included with each plan.&lt;/p&gt;
&lt;h2 id="give-it-a-try"&gt;Give it a try&lt;/h2&gt;
&lt;p&gt;Open a pull request against a stack Pulumi manages and see Neo&amp;rsquo;s review. We want to hear what it catches and what it misses, so hop into the &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; and tell us.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>ai</category><category>ai-agents</category><category>features</category><category>pulumi-neo</category></item><item><title>Trigger Deployments on Git Tags</title><link>https://www.pulumi.com/blog/trigger-deployments-on-git-tags/</link><pubDate>Fri, 05 Jun 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/trigger-deployments-on-git-tags/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/trigger-deployments-on-git-tags/index.png" /&gt;
&lt;p&gt;A git tag is how many teams mark a release as ready. Pulumi Deployments can now act on that signal directly: configure a tag-based trigger, push a version tag like &lt;code&gt;v1.2.0&lt;/code&gt;, and Pulumi automatically runs &lt;code&gt;pulumi up&lt;/code&gt; for your stack. No extra pipeline glue, no manual click — your release tag &lt;em&gt;is&lt;/em&gt; the deployment.&lt;/p&gt;
&lt;h2 id="why-tags"&gt;Why tags?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/deployments/deployments/using/triggers/#push-to-deploy"&gt;Push to Deploy&lt;/a&gt; has long let you preview changes on a pull request and update a stack when commits merge to a branch. That branch-based model is a great fit for continuous delivery to shared development and QA environments, where every merge should flow straight through.&lt;/p&gt;
&lt;p&gt;But promotion to production is often deliberate, not continuous. You merge throughout the day, then decide — separately — that a particular commit is the release. The conventional way to record that decision is a git tag: &lt;code&gt;v1.2.0&lt;/code&gt;, &lt;code&gt;2026.06.0&lt;/code&gt;, &lt;code&gt;release-2026-06-04&lt;/code&gt;. Tagging is already part of most teams&amp;rsquo; release rituals.&lt;/p&gt;
&lt;p&gt;Tag-based triggers connect that ritual to your infrastructure. Instead of wiring up a separate CI job to call the &lt;a href="https://www.pulumi.com/docs/deployments/deployments/using/triggers/#rest-api"&gt;Pulumi Deployments REST API&lt;/a&gt; on a tag event, you configure the trigger once in your stack&amp;rsquo;s deployment settings and let Pulumi handle the rest.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Tag triggers are controlled by two settings on your stack&amp;rsquo;s &lt;a href="https://www.pulumi.com/docs/deployments/deployments/using/settings/"&gt;deployment configuration&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Run updates for pushed tags&lt;/strong&gt; — a toggle that enables running &lt;code&gt;pulumi up&lt;/code&gt; when a matching tag is pushed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tag filters&lt;/strong&gt; — a list of glob patterns that decide which tag names qualify.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tag filters use the same model as the &lt;a href="https://www.pulumi.com/docs/deployments/deployments/using/settings/#path-filtering"&gt;path filters&lt;/a&gt; you may already know, except the patterns match against the tag name rather than changed file paths. A few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;v*&lt;/code&gt; — deploy on any tag beginning with &lt;code&gt;v&lt;/code&gt;, such as &lt;code&gt;v1.0.0&lt;/code&gt; and &lt;code&gt;v2.3.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v*&lt;/code&gt; plus &lt;code&gt;!*-rc*&lt;/code&gt; — deploy on release tags but skip release candidates like &lt;code&gt;v1.2.0-rc1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2026.*&lt;/code&gt; — deploy on calendar-versioned releases such as &lt;code&gt;2026.06.0&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Filters prefixed with &lt;code&gt;!&lt;/code&gt; are exclusions, and an exclusion always wins over an include. With no filters configured and the toggle on, every tag push deploys. Deleting a tag never triggers a deployment.&lt;/p&gt;
&lt;p&gt;When a tag push kicks off a deployment, Pulumi sets the &lt;code&gt;PULUMI_CI_TAG_NAME&lt;/code&gt; environment variable to the tag name. Your pre-run commands or your Pulumi program can read it — for example, to stamp the release version onto a resource tag or an application config value.&lt;/p&gt;
&lt;h2 id="works-across-every-vcs-integration"&gt;Works across every VCS integration&lt;/h2&gt;
&lt;p&gt;Tag triggers are available across all five version control integrations: &lt;a href="https://www.pulumi.com/docs/integrations/version-control/github-app/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/gitlab/"&gt;GitLab&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/bitbucket/"&gt;Bitbucket&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/azure-devops-integration/"&gt;Azure DevOps&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/integrations/version-control/custom-vcs/"&gt;Custom VCS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;You can configure tag triggers wherever you manage deployment settings today — the &lt;a href="https://app.pulumi.com/signin"&gt;Pulumi Cloud console&lt;/a&gt;, the &lt;a href="https://www.pulumi.com/docs/reference/cloud-rest-api/deployments/#patch-settings"&gt;REST API&lt;/a&gt;, or as code with the &lt;a href="https://www.pulumi.com/registry/packages/pulumiservice/api-docs/deploymentsettings/"&gt;&lt;code&gt;pulumiservice.DeploymentSettings&lt;/code&gt;&lt;/a&gt; resource.&lt;/p&gt;
&lt;p&gt;To try it out:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open a stack&amp;rsquo;s &lt;strong&gt;Settings &amp;gt; Deploy&lt;/strong&gt; tab in the Pulumi Cloud console.&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Run updates for pushed tags&lt;/strong&gt; and add a tag filter such as &lt;code&gt;v*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Push a tag — &lt;code&gt;git tag v1.0.0 &amp;amp;&amp;amp; git push origin v1.0.0&lt;/code&gt; — and watch the deployment run.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the full details, see the &lt;a href="https://www.pulumi.com/docs/deployments/deployments/using/triggers/#deploying-on-git-tags"&gt;deployment triggers&lt;/a&gt; and &lt;a href="https://www.pulumi.com/docs/deployments/deployments/using/settings/#tag-filtering"&gt;tag filtering&lt;/a&gt; documentation. We&amp;rsquo;d love to hear how you put tag-based deployments to work.&lt;/p&gt;</description><author>Michael Fallihee</author><category>features</category><category>pulumi-cloud</category><category>announcements</category></item><item><title>Introducing pulumi do: Direct Resource Operations for Any Cloud</title><link>https://www.pulumi.com/blog/pulumi-do-direct-resource-operations/</link><pubDate>Fri, 22 May 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-do-direct-resource-operations/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-do-direct-resource-operations/index.png" /&gt;
&lt;p&gt;Infrastructure as code is the right model for production systems. State tracking, drift detection, and repeatable deployments all matter when you&amp;rsquo;re managing real workloads.&lt;/p&gt;
&lt;p&gt;But sometimes, you also need a quick, one-off interaction with the cloud: create a bucket or a database, look up a VPC, delete a stray resource.&lt;/p&gt;
&lt;p&gt;Today we&amp;rsquo;re introducing &lt;code&gt;pulumi do&lt;/code&gt;, a new command for direct resource operations. With &lt;code&gt;pulumi do&lt;/code&gt;, you can create, read, update, delete, and query any cloud resource from the terminal with a single command, across thousands of Pulumi-supported providers — no project, code, or state required.&lt;/p&gt;
&lt;h2 id="the-problem-sometimes-iac-is-more-than-you-need"&gt;The problem: Sometimes IaC is more than you need&lt;/h2&gt;
&lt;p&gt;When you&amp;rsquo;re managing production workloads, IaC is the proven solution. Code lets you declare complex systems, state tracking catches drift before it becomes a problem, dependency graphs sequence changes safely, and policy keeps everything in bounds. That full lifecycle, especially with the backing of a platform like Pulumi Cloud, is exactly what you want to build systems that scale.&lt;/p&gt;
&lt;p&gt;But when you (or your coding agent) need an ad-hoc Postgres database, the simplest path with IaC still takes several steps: make a directory, create a project, configure your credentials, write the code, preview, deploy. It works, but it&amp;rsquo;s not always necessary for what should be a simple operation. &lt;code&gt;pulumi do&lt;/code&gt; collapses all of those steps into one, using the same Pulumi providers, resource model, and ecosystem that powers the core Pulumi platform.&lt;/p&gt;
&lt;p&gt;Resource creation is also only part of the problem. As Joe laid out in &lt;a href="https://www.pulumi.com/blog/the-agentic-infrastructure-era/"&gt;The Agentic Infrastructure Era&lt;/a&gt;, the real challenge for AI agents isn&amp;rsquo;t with code or CLI commands, it&amp;rsquo;s with everything else: getting a cloud account, resolving credentials, wiring configuration across multiple services. &lt;a href="https://www.pulumi.com/docs/administration/organizations-teams/agent-accounts/"&gt;Agent accounts&lt;/a&gt;, also &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;released this week&lt;/a&gt;, simplify this by letting an agent provision its own ephemeral Pulumi Cloud account, and &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; takes care of consolidating credentials across providers. Together, with &lt;code&gt;pulumi do&lt;/code&gt;, agents can now go from zero to deployed infrastructure without requiring a human in the loop — and when that one-off resource needs to grow into a more permanent system, there&amp;rsquo;s a clear graduation path back to full Pulumi IaC.&lt;/p&gt;
&lt;h2 id="what-it-looks-like"&gt;What it looks like&lt;/h2&gt;
&lt;p&gt;As an example, say you wanted to provision an S3 bucket. With the AWS CLI, you&amp;rsquo;d need to assemble an &lt;code&gt;aws s3api create-bucket&lt;/code&gt; invocation with the right set of command-line flags, region constraints, a globally unique name, and so on. With &lt;code&gt;pulumi do&lt;/code&gt;, it&amp;rsquo;s just this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket create
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That might not look all that different on the surface — but because you&amp;rsquo;re using the Pulumi engine and resource model, you can provide a minimal set of input properties, take advantage of provider-defined defaults, and use Pulumi&amp;rsquo;s &lt;a href="https://www.pulumi.com/docs/iac/concepts/resources/names/"&gt;auto-naming&lt;/a&gt; feature to give the bucket a unique name automatically:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket create
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;This will create aws:s3/bucket:Bucket with the following inputs:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;bucket&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;bucket-279ea56&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;tagsAll&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Please confirm that this is what you&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;d like to &lt;span class="k"&gt;do&lt;/span&gt; by typing &lt;span class="sb"&gt;`&lt;/span&gt;yes&lt;span class="sb"&gt;`&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Answer &lt;code&gt;yes&lt;/code&gt; (or just pass &lt;code&gt;--yes&lt;/code&gt;), and you&amp;rsquo;re done. To delete the bucket:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket delete bucket-279ea56 --yes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Need to look up an existing resource? Use a &lt;a href="https://www.pulumi.com/docs/iac/concepts/functions/provider-functions/"&gt;provider function&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:ec2:getVpc --default
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;arn&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;arn:aws:ec2:us-west-2:663782525873:vpc/vpc-d7b311af&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;cidrBlock&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;172.31.0.0/16&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;enableDnsHostnames&amp;#34;&lt;/span&gt;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;enableDnsSupport&amp;#34;&lt;/span&gt;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;enableNetworkAddressUsageMetrics&amp;#34;&lt;/span&gt;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;vpc-d7b311af&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Same CLI, same output contract, same provider ecosystem.&lt;/p&gt;
&lt;h3 id="the-command-shape"&gt;The command shape&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;do&lt;/code&gt; command accepts a Pulumi resource type, or &lt;a href="https://www.pulumi.com/docs/iac/concepts/resources/names/#types"&gt;&lt;em&gt;type token&lt;/em&gt;&lt;/a&gt;, to determine the action to take. Type tokens have the form &lt;code&gt;&amp;lt;package:module:resource&amp;gt;&lt;/code&gt;. For example, &lt;code&gt;aws:s3:Bucket&lt;/code&gt; refers to the &lt;a href="https://www.pulumi.com/registry/packages/aws/api-docs/s3/bucket/"&gt;Amazon S3 Bucket resource&lt;/a&gt; that belongs to the &lt;code&gt;s3&lt;/code&gt; module of the &lt;code&gt;aws&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;You can also provide a portion of the token to help you find what you&amp;rsquo;re looking for without ever having to leave the terminal:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Functions and resources &lt;span class="k"&gt;for&lt;/span&gt; the s3 module.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Run &lt;span class="s1"&gt;&amp;#39;pulumi do &amp;lt;module/resource/function&amp;gt; --help&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; more details on usage.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Functions:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:getAccessPoint
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:getAccountPublicAccessBlock
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:getBucket
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:getBucketObject
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:AccessPoint
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:AccountPublicAccessBlock
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:AnalyticsConfiguration
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:Bucket
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket &lt;span class="nb"&gt;read&lt;/span&gt; bucket-d20976f
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;arn&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;arn:aws:s3:::bucket-d20976f&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;bucket&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;bucket-d20976f&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;bucketDomainName&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;bucket-d20976f.s3.amazonaws.com&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;bucketNamespace&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;global&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The package, module, and resource/function segments all come directly from the Pulumi provider schema, so &lt;code&gt;--help&lt;/code&gt; works at every level of the tree. Pass a package name, optional module, and optional function or resource type, and &lt;code&gt;do&lt;/code&gt; returns the appropriate level of detail.&lt;/p&gt;
&lt;p&gt;You can also provide the input properties of a resource in a YAML or JSON file with the &lt;code&gt;--input&lt;/code&gt; option. To create a container service in Google Cloud Run for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# service.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;us-central1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;deletionProtection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;us-docker.pkg.dev/cloudrun/container/hello&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; gcp:cloudrunv2:Service create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --input yaml &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --input-file service.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;This will create gcp:cloudrunv2/service:Service with the following inputs:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;deletionProtection&amp;#34;&lt;/span&gt;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;location&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;us-central1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;service-b8af752&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;template&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;containers&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;image&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;us-docker.pkg.dev/cloudrun/container/hello&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;createTime&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2026-05-22T23:00:22.415839Z&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;urls&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://service-b8af752-921927215178.us-central1.run.app&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://service-b8af752-ctnulmzwoa-uc.a.run.app&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="resource-operations"&gt;Resource operations&lt;/h3&gt;
&lt;p&gt;Most resources support the full set of CRUD operations — create, read, update, delete, and list — directly from the CLI. Each operation maps to a provider CRUD method using the same provider logic a full Pulumi program would use, and resources are addressable by their cloud provider IDs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Create a resource&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket create --yes &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s2"&gt;&amp;#34;.name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bucket-4f5cb22
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Fetch it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket &lt;span class="nb"&gt;read&lt;/span&gt; bucket-4f5cb22 &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s2"&gt;&amp;#34;.hostedZoneId&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Z3BJ6K6RIION7M
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Update/patch it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket patch bucket-4f5cb22 --input yaml --input-file tags.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket &lt;span class="nb"&gt;read&lt;/span&gt; bucket-4f5cb22 &lt;span class="p"&gt;|&lt;/span&gt; jq &lt;span class="s2"&gt;&amp;#34;.tags&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Delete it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket delete bucket-4f5cb22
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="provider-configuration"&gt;Provider configuration&lt;/h3&gt;
&lt;p&gt;Today, &lt;code&gt;pulumi do&lt;/code&gt; resolves provider configuration — for example, applying your AWS credentials — using environment variables or credential files as supported by each individual Pulumi provider. See the &lt;a href="https://www.pulumi.com/registry/"&gt;Pulumi Registry&lt;/a&gt; for provider-specific configuration details.&lt;/p&gt;
&lt;h2 id="designed-for-humans-and-agents"&gt;Designed for humans and agents&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ve designed &lt;code&gt;pulumi do&lt;/code&gt; to serve humans and coding agents equally well, guided by three fundamental ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Consistent command structure across every provider.&lt;/strong&gt; The &lt;code&gt;do &amp;lt;package:module:type&amp;gt; &amp;lt;operation&amp;gt;&lt;/code&gt; pattern is the same for AWS, Azure, Google Cloud, Kubernetes, Cloudflare, Datadog, and every provider, including packages containing higher-level &lt;a href="https://www.pulumi.com/docs/iac/concepts/components/"&gt;component resources&lt;/a&gt;. Once an agent learns that pattern, it applies across the board.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Predictable output contract.&lt;/strong&gt; JSON on stdout, progress on stderr, consistent exit codes. An agent can parse the result programmatically without scraping human-formatted tables.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A single CLI command that works across every cloud.&lt;/strong&gt; Many cloud and SaaS providers don&amp;rsquo;t have a full CLI at all. &lt;code&gt;pulumi do&lt;/code&gt; generates commands from the provider schema, so if a Pulumi provider exists for it, the CLI just works. Neither humans nor agents need to install, learn, or even know about cloud provider-specific tooling.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="whats-next"&gt;What&amp;rsquo;s next&lt;/h2&gt;
&lt;p&gt;Resource operations and provider functions are the foundation. The &lt;code&gt;pulumi do&lt;/code&gt; roadmap extends the same direct-operation model with credential management, state tracking, and a path to full IaC.&lt;/p&gt;
&lt;h3 id="unified-credentials-with-pulumi-esc"&gt;Unified credentials with Pulumi ESC&lt;/h3&gt;
&lt;p&gt;One of the hardest parts of multi-cloud operations is credential management. Every provider has its own authentication scheme, environment variables, and session lifecycle. An agent working across AWS, Cloudflare, and Datadog today manages three separate credential mechanisms.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re building &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; integration into &lt;code&gt;pulumi do&lt;/code&gt; so you can manage credentials in one place and resolve them everywhere. ESC handles credential resolution (including OIDC-based dynamic credential generation and short-lived tokens) across all of your providers. Name the credential set, reference it, and ESC does the rest, with rotation, RBAC, and audit built in.&lt;/p&gt;
&lt;h3 id="cross-resource-references"&gt;Cross-resource references&lt;/h3&gt;
&lt;p&gt;Real infrastructure has dependencies — subnets need VPCs, security group rules need their security groups, and so on. When you&amp;rsquo;re building resources one at a time, those references need to flow between commands somehow.&lt;/p&gt;
&lt;p&gt;A future version of &lt;code&gt;pulumi do&lt;/code&gt; will let resource inputs reference outputs from previously created resources, allowing the CLI to resolve them automatically and preserve the dependency graph. Later, when the time comes to graduate to a full IaC program, the generated code contains proper resource references rather than hard-coded strings.&lt;/p&gt;
&lt;h3 id="stateful-mode-and-the-graduation-path"&gt;Stateful mode and the graduation path&lt;/h3&gt;
&lt;p&gt;Today, &lt;code&gt;pulumi do&lt;/code&gt; is stateless. Each command runs independently. A planned stateful mode will persist resource state across operations, enabling drift detection, lifecycle management, and a graduation path to full infrastructure as code.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what we&amp;rsquo;re planning:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zero setup.&lt;/strong&gt; Your first &lt;code&gt;pulumi do&lt;/code&gt; implicitly creates a project and stack. No manual initialization.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Accumulate resources.&lt;/strong&gt; Each operation stores resource state. After a few commands, you have a lightweight representation of your infrastructure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Eject to a full project.&lt;/strong&gt; When the time comes, generate a Pulumi project in your chosen language with all resources imported and dependency graphs intact.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Connect to Pulumi Cloud.&lt;/strong&gt; Layer on governance, compliance, team collaboration, and deployment automation through &lt;a href="https://www.pulumi.com/product/"&gt;Pulumi Cloud&lt;/a&gt;. Resources created via &lt;code&gt;pulumi do&lt;/code&gt; can be governed by &lt;a href="https://www.pulumi.com/product/insights-governance/"&gt;Pulumi Insights&lt;/a&gt; from day one, even before you opt into full IaC.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This path works because &lt;code&gt;pulumi do&lt;/code&gt; uses the same providers, resource types, and property schemas as every other &lt;code&gt;pulumi&lt;/code&gt; operation. Provisioned cloud resources stay where they are as management capabilities are added as needed.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pulumi do&lt;/code&gt; ships as a research preview in &lt;a href="https://github.com/pulumi/pulumi/releases/tag/v3.242.0"&gt;Pulumi CLI v3.242.0&lt;/a&gt; and later. Install or update the CLI, install a provider plugin, and start running commands. The &lt;a href="https://www.pulumi.com/docs/iac/cli/direct-resource-operations/"&gt;documentation&lt;/a&gt; has the full reference.&lt;/p&gt;
&lt;p&gt;We can&amp;rsquo;t wait to hear your feedback. &lt;a href="https://www.pulumi.com/docs/install/"&gt;Give it a try today&lt;/a&gt;, tell us what works (and what doesn&amp;rsquo;t), and help shape the CLI that agents and humans both reach for first.&lt;/p&gt;</description><author>Fraser Waters</author><author>Pat Gavlin</author><author>Arun Loganathan</author><author>Christian Nunciato</author><category>features</category><category>pulumi-cli</category><category>ai-agents</category><category>product-launches</category></item><item><title>Bringing Neo to GitHub and Slack</title><link>https://www.pulumi.com/blog/neo-github-slack/</link><pubDate>Thu, 21 May 2026 08:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/neo-github-slack/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-github-slack/index.png" /&gt;
&lt;p&gt;This week, &lt;a href="https://www.pulumi.com/blog/pulumi-neo/"&gt;Pulumi Neo&lt;/a&gt; started working in two more places: GitHub and Slack. The agent that already runs Pulumi tasks from the Cloud console and the &lt;a href="https://www.pulumi.com/blog/pulumi-neo-cli/"&gt;terminal&lt;/a&gt; now participates in the threads where your team discusses changes.&lt;/p&gt;
&lt;p&gt;Mention &lt;code&gt;@pulumi-neo&lt;/code&gt; in a &lt;a href="https://www.pulumi.com/docs/ai/code-reviews/"&gt;pull request or issue&lt;/a&gt; and Neo replies in the thread. Mention &lt;code&gt;@Neo&lt;/code&gt; in a &lt;a href="https://www.pulumi.com/docs/ai/integrations/slack/"&gt;Slack channel&lt;/a&gt; and Neo starts a &lt;a href="https://www.pulumi.com/docs/ai/tasks/"&gt;task&lt;/a&gt;, continuing the conversation as you reply.&lt;/p&gt;
&lt;h2 id="neo-in-github"&gt;Neo in GitHub&lt;/h2&gt;
&lt;p&gt;Mention &lt;code&gt;@pulumi-neo&lt;/code&gt; in a pull request description, a top-level or inline review comment, or an issue. Neo sees the diff, the stacks linked to the repository, and their current state. Reviewers can ask Neo to walk through what a proposed change does, including resources that change in stacks the PR doesn&amp;rsquo;t touch directly. Responses land in the same thread, so the analysis becomes part of the review record and any follow-up stays with it.&lt;/p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Delegating a GitHub issue to Neo"
autoplay muted playsinline
loop &gt;
&lt;source src="neo-github.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;h2 id="neo-in-slack"&gt;Neo in Slack&lt;/h2&gt;
&lt;p&gt;Mention &lt;code&gt;@Neo&lt;/code&gt; in any channel where Neo has been added, and Neo starts a task in the thread. The reply lands in the same thread, and follow-up messages continue the conversation there. The rest of the channel can see what was asked and what Neo found. Neo has the same capabilities here as in the Pulumi Cloud console or the terminal: check stack state, investigate failures, walk through what a change will do, or carry out actions the team has approved.&lt;/p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Tagging Neo for help with an issue in Slack"
autoplay muted playsinline
loop &gt;
&lt;source src="neo-slack.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;h2 id="integrations-in-action"&gt;Integrations in action&lt;/h2&gt;
&lt;p&gt;A teammate posts in &lt;code&gt;#platform-engineering&lt;/code&gt;: &amp;ldquo;API latency p95 has been climbing for two days, nobody can figure out why.&amp;rdquo; You reply:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; @Neo check the production API stack. Anything change in the last 72 hours?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo starts a task in the thread, walks the stack history, and finds a configuration change to the load balancer&amp;rsquo;s idle-timeout setting that landed Friday afternoon. It posts the change, who deployed it, and when. The rest of the channel sees the finding without you having to retell it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; @Neo open a PR to revert idle-timeout to the previous value.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo edits the stack&amp;rsquo;s Pulumi program, runs &lt;code&gt;pulumi preview&lt;/code&gt; to confirm the change touches only the load balancer, and opens a pull request with the diff and the preview output. A reviewer pulls it up:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Reviewer:&lt;/strong&gt; @pulumi-neo what else does this change affect downstream?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo replies in the same review thread with the resources that change: the listener config and the target group health check. The reviewer reads, approves, and the change ships.&lt;/p&gt;
&lt;p&gt;The investigation moved from Slack to GitHub, and both threads keep the record.&lt;/p&gt;
&lt;h2 id="permissions-and-governance"&gt;Permissions and governance&lt;/h2&gt;
&lt;p&gt;Whether the conversation starts in GitHub or Slack, Neo runs with the &lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/"&gt;RBAC permissions&lt;/a&gt; of your Pulumi Cloud user. Stack-level controls, organization-level guardrails, and audit logging apply the same way they do for a task started from the console. Starting a conversation in a new place doesn&amp;rsquo;t grant Neo new permissions; it just changes where the conversation happens.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Both integrations are available now for Neo-enabled organizations. The &lt;a href="https://www.pulumi.com/docs/ai/code-reviews/"&gt;Code Reviews docs&lt;/a&gt; and &lt;a href="https://www.pulumi.com/docs/ai/integrations/slack/"&gt;Slack integration docs&lt;/a&gt; cover the one-time setup. From there, every engineer with a linked Pulumi Cloud identity can mention Neo from the threads they already work in.&lt;/p&gt;
&lt;p&gt;Today&amp;rsquo;s launch is part of a &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;bigger story&lt;/a&gt;. Read our launch-day piece on &lt;a href="https://www.pulumi.com/blog/the-agentic-infrastructure-era/"&gt;the agentic infrastructure era&lt;/a&gt; for the broader vision, the &lt;a href="https://www.pulumi.com/blog/pulumi-neo-cli/"&gt;Neo CLI launch post&lt;/a&gt; for Neo&amp;rsquo;s new home in the terminal, and the &lt;a href="https://www.pulumi.com/blog/neo-integrations/"&gt;Neo Integrations post&lt;/a&gt; for the MCP servers and cloud CLIs that ship with this release.&lt;/p&gt;
&lt;p&gt;As always, we&amp;rsquo;d love to hear what you think — and if you have any suggestions for places we should put Neo next, file an issue in &lt;a href="https://github.com/pulumi/pulumi-cloud-requests/issues/new/choose"&gt;pulumi-cloud-requests&lt;/a&gt;.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>ai</category><category>ai-agents</category><category>features</category><category>pulumi-neo</category></item><item><title>Neo Automations: Scheduled Tasks Shipped as Pull Requests</title><link>https://www.pulumi.com/blog/neo-automations/</link><pubDate>Thu, 21 May 2026 07:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/neo-automations/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-automations/index.png" /&gt;
&lt;p&gt;Recurring platform work slips: provider versions fall behind, drift accumulates between checks, and the quarterly audit keeps getting pushed back another month. &lt;a href="https://www.pulumi.com/blog/pulumi-neo/"&gt;Pulumi Neo&lt;/a&gt; can now run any &lt;a href="https://www.pulumi.com/docs/ai/tasks/"&gt;task&lt;/a&gt; on a cadence you set, opening a pull request for each run.&lt;/p&gt;
&lt;h2 id="automations-in-action"&gt;Automations in action&lt;/h2&gt;
&lt;p&gt;Your platform team runs stacks across staging and production, and the &lt;a href="https://www.pulumi.com/registry/packages/aws/"&gt;AWS&lt;/a&gt;, &lt;a href="https://www.pulumi.com/registry/packages/gcp/"&gt;GCP&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/registry/packages/kubernetes/"&gt;Kubernetes&lt;/a&gt; providers keep shipping new versions. Nobody has time to bump them stack by stack.&lt;/p&gt;
&lt;p&gt;You write one automation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every Monday at 8 AM, check the &lt;code&gt;infra/&lt;/code&gt; project for stacks where the AWS, GCP, or Kubernetes provider is more than two minor versions behind. For each one, bump the out-of-date provider, run &lt;code&gt;pulumi preview&lt;/code&gt;, and open a PR if the preview is clean.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Monday morning, Neo runs the prompt. It finds three stacks behind on the AWS provider, edits each program, runs preview, and opens a PR for each clean run. You review the PRs like you would any other dependency bump, merge them, and Neo runs again next Monday.&lt;/p&gt;
&lt;h2 id="what-automations-are-for"&gt;What automations are for&lt;/h2&gt;
&lt;p&gt;The launch includes four built-in templates: a provider freshness check, an encryption audit, a backup audit, and an activity digest. You can also skip the templates and write your own prompt.&lt;/p&gt;
&lt;p&gt;Pick from hourly, daily, weekdays, or weekly cadences. Each automation gets its own page in the &lt;strong&gt;Automations&lt;/strong&gt; tab, where you can edit the prompt, change the schedule, run it once on demand, or pause it.&lt;/p&gt;
&lt;h2 id="safe-by-default"&gt;Safe by default&lt;/h2&gt;
&lt;p&gt;Automations default to two settings that fit recurring work. Approval mode is &lt;a href="https://www.pulumi.com/docs/ai/tasks/#task-modes"&gt;&lt;strong&gt;auto&lt;/strong&gt;&lt;/a&gt;, so a run doesn&amp;rsquo;t wait for human confirmation between steps. Permission mode is &lt;a href="https://www.pulumi.com/docs/ai/tasks/#task-modes"&gt;&lt;strong&gt;read-only&lt;/strong&gt;&lt;/a&gt;, so a run can read state and propose changes through pull requests but can&amp;rsquo;t apply changes directly. You can override either default per automation.&lt;/p&gt;
&lt;h2 id="how-automations-fit-with-the-rest-of-neo"&gt;How automations fit with the rest of Neo&lt;/h2&gt;
&lt;p&gt;A scheduled task uses the same context as an interactive Neo task. &lt;a href="https://www.pulumi.com/docs/ai/settings/"&gt;Custom Instructions&lt;/a&gt; at the organization and project level apply, so a scheduled run respects the same naming conventions, tagging policies, and architecture rules your team has written down.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/"&gt;MCP integrations&lt;/a&gt; and &lt;a href="https://www.pulumi.com/docs/ai/integrations/cli/"&gt;CLI integrations&lt;/a&gt; work in scheduled tasks the same way they work in interactive ones, so a weekly drift check can query AWS through the &lt;code&gt;aws&lt;/code&gt; CLI, file &lt;a href="https://linear.app/"&gt;Linear&lt;/a&gt; issues, and link related &lt;a href="https://www.pagerduty.com/"&gt;PagerDuty&lt;/a&gt; incidents. Scheduled tasks also run with the &lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/"&gt;RBAC permissions&lt;/a&gt; of the user who scheduled them, checked at run time; if permissions change between scheduling and execution, the new permissions apply.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Open Neo in &lt;a href="https://www.pulumi.com/product/pulumi-cloud/"&gt;Pulumi Cloud&lt;/a&gt;, switch to the &lt;strong&gt;Automations&lt;/strong&gt; tab, and pick a template or write your own prompt. The &lt;a href="https://www.pulumi.com/docs/ai/automations/"&gt;automations docs&lt;/a&gt; cover the form, scheduling options, and per-automation overrides.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/neo-automations/neo-freshness.check.png" alt="Setting up a scheduled task for Pulumi Neo"&gt;&lt;/p&gt;
&lt;p&gt;Today&amp;rsquo;s launch is part of a &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;bigger story&lt;/a&gt;. Read our launch-day piece on &lt;a href="https://www.pulumi.com/blog/the-agentic-infrastructure-era/"&gt;the agentic infrastructure era&lt;/a&gt; for the broader vision, and the &lt;a href="https://www.pulumi.com/blog/neo-integrations/"&gt;Neo Integrations post&lt;/a&gt; for the third-party tools and CLIs your automations can use.&lt;/p&gt;
&lt;p&gt;As always, we&amp;rsquo;d love to hear what you think — and if you have any suggestions for automations that&amp;rsquo;d make Neo even better, file an issue in &lt;a href="https://github.com/pulumi/pulumi-cloud-requests/issues/new/choose"&gt;pulumi-cloud-requests&lt;/a&gt;.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>ai</category><category>ai-agents</category><category>features</category><category>pulumi-neo</category></item><item><title>Neo, Now in the Terminal</title><link>https://www.pulumi.com/blog/pulumi-neo-cli/</link><pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-neo-cli/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-neo-cli/index.png" /&gt;
&lt;p&gt;Since launching &lt;a href="https://www.pulumi.com/blog/pulumi-neo/"&gt;Pulumi Neo&lt;/a&gt;, over 4,500 organizations have used it to delegate real infrastructure work: scaffolding, migrating, investigating, operationalizing, and more. Though that usage has come entirely through Pulumi Cloud, we know a large portion of Pulumi users live in the terminal, and increasingly that&amp;rsquo;s where AI tools run too. Now we&amp;rsquo;re bringing Neo there.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pulumi neo&lt;/code&gt; brings the same Neo experience you&amp;rsquo;ve had in Pulumi Cloud to your terminal. Running locally means there&amp;rsquo;s no separate branch to push, no credentials to provision, and no context to paste: Neo picks up the setup you already have.&lt;/p&gt;
&lt;p&gt;&lt;img src="tui.png" alt="pulumi neo working through a Kubernetes cluster check, with Flux GitOps state verified and a TODO list in progress"&gt;&lt;/p&gt;
&lt;h2 id="what-local-execution-unlocks"&gt;What local execution unlocks&lt;/h2&gt;
&lt;p&gt;Neo inherits your setup when it runs locally. The CLIs you&amp;rsquo;ve authenticated, the environment variables and kubeconfigs you&amp;rsquo;ve configured, and the project you&amp;rsquo;re editing right now are all available without any setup on your part. That means Neo can run the same commands you would, against the same systems you have access to.&lt;/p&gt;
&lt;p&gt;That makes &lt;code&gt;pulumi neo&lt;/code&gt; a fit for paired, interactive sessions where you and Neo work through a problem together. For asynchronous, autonomous tasks you set up and come back to, Pulumi Cloud Neo is still the surface to reach for. Both reach the same Neo.&lt;/p&gt;
&lt;p&gt;You can also hand tasks to Neo from other agent sessions. Simply ask your agent, such as Claude Code or Codex, to hand the task off to Neo, and the &lt;a href="https://github.com/pulumi/agent-skills/tree/main/delegation"&gt;Neo handoff skill&lt;/a&gt; packages the current thread (goal, repo pointers, conversation summary) and starts a Neo task using &lt;code&gt;pulumi neo&lt;/code&gt; under the hood. This works anywhere skills are supported, without leaving your current session.&lt;/p&gt;
&lt;h2 id="what-carries-over"&gt;What carries over&lt;/h2&gt;
&lt;p&gt;Local tools and context are what&amp;rsquo;s new. The full set of controls you have in Pulumi Cloud Neo applies in the terminal: approval modes (manual, balanced, auto) for tool calls, permission modes (default, read-only) for what Neo can change, and &lt;a href="https://www.pulumi.com/docs/ai/tasks/#plan-mode"&gt;Plan Mode&lt;/a&gt; for research and planning before execution.&lt;/p&gt;
&lt;p&gt;Integrations carry over too. The &lt;a href="https://www.pulumi.com/blog/neo-integration-catalog/"&gt;integration catalog&lt;/a&gt; (connectors to Atlassian, Datadog, Linear, PagerDuty, and others) works the same way from the terminal. Identity, RBAC, and audit all run through your &lt;code&gt;pulumi login&lt;/code&gt;, the same way they do in the console. See the &lt;a href="https://www.pulumi.com/docs/ai/"&gt;Pulumi Neo docs&lt;/a&gt; for details.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pulumi neo&lt;/code&gt; ships with the latest Pulumi CLI. To start a session:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Authenticate to Pulumi Cloud with &lt;code&gt;pulumi login&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pulumi neo&lt;/code&gt;, or pass an initial prompt: &lt;code&gt;pulumi neo &amp;quot;what's in this stack?&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;pulumi neo&lt;/code&gt; is part of a &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;broader launch&lt;/a&gt; on &lt;a href="https://www.pulumi.com/blog/the-agentic-infrastructure-era/"&gt;agentic infrastructure&lt;/a&gt;. See the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_neo/"&gt;&lt;code&gt;pulumi neo&lt;/code&gt; command reference&lt;/a&gt; and the &lt;a href="https://www.pulumi.com/docs/ai/"&gt;Pulumi Neo docs&lt;/a&gt; for details. &lt;a href="https://www.pulumi.com/blog/10-things-you-can-do-with-neo/"&gt;10 things you can do with Neo&lt;/a&gt; is a good starting point for tasks to try. The &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; is the place for questions and feedback.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>ai</category><category>ai-agents</category><category>features</category><category>pulumi-neo</category><category>pulumi-cli</category></item><item><title>Neo Integrations: MCP Servers and Cloud CLIs</title><link>https://www.pulumi.com/blog/neo-integrations/</link><pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/neo-integrations/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-integrations/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/product/neo/"&gt;Pulumi Neo&lt;/a&gt; already understands your infrastructure: your code, your stacks, your state. Today we&amp;rsquo;re launching new capabilities that extend Neo&amp;rsquo;s reach in two directions: into the third-party systems your team uses to plan and observe, and out to the cloud CLIs that actually drive your infrastructure.&lt;/p&gt;
&lt;p&gt;The first half is MCP integrations: connections to &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#atlassian-jira-and-confluence"&gt;Atlassian&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#datadog"&gt;Datadog&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#honeycomb"&gt;Honeycomb&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#linear"&gt;Linear&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#pagerduty"&gt;PagerDuty&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#supabase"&gt;Supabase&lt;/a&gt; that show up as tools Neo can call during a &lt;a href="https://www.pulumi.com/docs/ai/tasks/"&gt;task&lt;/a&gt;. The second half is CLI integrations: scopable access to &lt;a href="https://www.pulumi.com/docs/ai/integrations/cli/#supported-clis"&gt;&lt;code&gt;aws&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/integrations/cli/#supported-clis"&gt;&lt;code&gt;gcloud&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/integrations/cli/#supported-clis"&gt;&lt;code&gt;az&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/ai/integrations/cli/#supported-clis"&gt;&lt;code&gt;kubectl&lt;/code&gt;&lt;/a&gt;. Both are configured once at the org level and available to every Neo task in the organization.&lt;/p&gt;
&lt;h2 id="integrations-in-action"&gt;Integrations in action&lt;/h2&gt;
&lt;p&gt;A PagerDuty alert just fired: RDS storage on &lt;code&gt;payments-prod&lt;/code&gt; is at 90% and climbing. You want to know how fast, and whether you can buy yourself any runway before it fills.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; Neo, RDS storage on &lt;code&gt;payments-prod&lt;/code&gt; just paged at 90%. How fast is it growing, and what do we have configured?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo pulls the active incident from PagerDuty, decides on its own to check Datadog for the storage-utilization curve over the last 30 days, and runs &lt;code&gt;aws rds describe-db-instances --db-instance-identifier payments-prod&lt;/code&gt; through your &lt;code&gt;production-aws&lt;/code&gt; CLI integration (the name your org gave its production AWS credentials). The database has been growing about 5 GB a day. The instance has &lt;code&gt;AllocatedStorage&lt;/code&gt; at 200 GB and &lt;code&gt;MaxAllocatedStorage&lt;/code&gt; also at 200, so storage autoscaling is effectively disabled. At current growth, the disk fills in three days.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; Bump max allocated storage to 500. Open a PR.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo edits the &lt;code&gt;payments&lt;/code&gt; stack&amp;rsquo;s Pulumi program to raise &lt;code&gt;maxAllocatedStorage&lt;/code&gt; from 200 to 500 on the RDS instance, runs &lt;code&gt;pulumi preview&lt;/code&gt; to confirm the change is scoped to that one resource, and opens a pull request with the diff, the preview output, and links to the PagerDuty incident and the Datadog graph. You review the PR and merge it. Pulumi applies the change, and Neo posts the resolution back to PagerDuty.&lt;/p&gt;
&lt;p&gt;With three integrations and one conversation, the change is reviewed, shipped, and the alert resolved a few minutes later.&lt;/p&gt;
&lt;h2 id="mcp-integrations-context-from-your-existing-tools"&gt;MCP integrations: context from your existing tools&lt;/h2&gt;
&lt;p&gt;The launch catalog covers six services that show up most often in infrastructure investigations: &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#atlassian-jira-and-confluence"&gt;Atlassian&lt;/a&gt; for Jira issues and Confluence runbooks, &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#datadog"&gt;Datadog&lt;/a&gt; for metrics and logs, &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#honeycomb"&gt;Honeycomb&lt;/a&gt; for traces, &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#linear"&gt;Linear&lt;/a&gt; for issue tracking, &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#pagerduty"&gt;PagerDuty&lt;/a&gt; for incidents and on-call schedules, and &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/#supabase"&gt;Supabase&lt;/a&gt; for managed database changes. Each connects Neo to a remote MCP server hosted by the provider, so the agent has access to the full set of tools the vendor chooses to expose.&lt;/p&gt;
&lt;p&gt;Integrations can be enabled by organization administrators on the Neo Settings page. Once configured, they&amp;rsquo;re available to every Neo task in your organization.&lt;/p&gt;
&lt;p&gt;&lt;img src="mcp-integrations.png" alt="Neo Settings showing the six available MCP integrations: Atlassian, Datadog, Honeycomb, Linear, PagerDuty, and Supabase"&gt;&lt;/p&gt;
&lt;h2 id="cli-integrations-live-cloud-insights"&gt;CLI integrations: live cloud insights&lt;/h2&gt;
&lt;p&gt;CLI integrations cover what MCP doesn&amp;rsquo;t reach: live cloud insights. With AWS, GCP, Azure, or Kubernetes connected, Neo can check live database utilization, look up the current state of a running service, verify a service quota before scaling, or reach into resources that aren&amp;rsquo;t managed by any Pulumi stack.&lt;/p&gt;
&lt;p&gt;An admin enables a CLI integration the same way as an MCP one, from your org&amp;rsquo;s Neo settings. Each integration gets a name your team chooses, like &lt;code&gt;production-aws&lt;/code&gt; or &lt;code&gt;staging-gcloud&lt;/code&gt;, and tasks reference that name to tell Neo which environment to reach into. You can connect multiple instances of the same CLI (for example, &lt;code&gt;production-aws&lt;/code&gt; and &lt;code&gt;staging-aws&lt;/code&gt;) so Neo can investigate staging without touching production. Credentials are backed by &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; environments your org owns; the &lt;a href="https://www.pulumi.com/docs/ai/integrations/cli/"&gt;CLI integrations docs&lt;/a&gt; walk through setup.&lt;/p&gt;
&lt;p&gt;&lt;img src="cli-integrations.png" alt="Neo Settings CLI tools tab with two connected AWS and Kubernetes integrations and four available CLI types: AWS, Google Cloud, Azure, and Kubernetes"&gt;&lt;/p&gt;
&lt;h2 id="per-task-control-and-failure-handling"&gt;Per-task control and failure handling&lt;/h2&gt;
&lt;p&gt;Both surfaces default to org-wide availability, with per-task overrides. Before starting a task, you can toggle individual MCP integrations off. The toggles only affect that task; the org-level configuration is unchanged.&lt;/p&gt;
&lt;p&gt;&lt;img src="per-task-toggles.png" alt="Neo task composer showing the Integrations menu with toggles for the Linear MCP server and two connected CLI integrations"&gt;&lt;/p&gt;
&lt;p&gt;Failures behave the same way for both. If an integration can&amp;rsquo;t be reached, Neo logs a warning, skips it, and continues with the rest. A single broken integration doesn&amp;rsquo;t stop a task. CLI integration connect and disconnect events go to your organization&amp;rsquo;s audit log, and Neo&amp;rsquo;s individual CLI calls appear in the task transcript alongside its other tool calls.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Both MCP and CLI integrations are available now for Neo-enabled organizations. Open your org&amp;rsquo;s Neo settings, connect the MCP server or CLI of your choice, and let Neo do the next investigation against the tools you already use. The &lt;a href="https://www.pulumi.com/docs/ai/integrations/mcp/"&gt;MCP integrations docs&lt;/a&gt; and &lt;a href="https://www.pulumi.com/docs/ai/integrations/cli/"&gt;CLI integrations docs&lt;/a&gt; walk through credential setup for each one, and the &lt;a href="https://www.pulumi.com/docs/ai/integrations/"&gt;Neo integrations hub&lt;/a&gt; ties it all together.&lt;/p&gt;
&lt;p&gt;Today&amp;rsquo;s launch is part of a &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;bigger story&lt;/a&gt;. Read our launch-day piece on &lt;a href="https://www.pulumi.com/blog/the-agentic-infrastructure-era/"&gt;the agentic infrastructure era&lt;/a&gt; for the broader vision, and the &lt;a href="https://www.pulumi.com/blog/pulumi-neo-cli/"&gt;Neo CLI launch post&lt;/a&gt; for Neo&amp;rsquo;s new home in the terminal.&lt;/p&gt;
&lt;p&gt;As always, we&amp;rsquo;d love to hear what you think — and if you have any suggestions for integrations that&amp;rsquo;d make Neo even better, file an issue in &lt;a href="https://github.com/pulumi/pulumi-cloud-requests/issues/new/choose"&gt;pulumi-cloud-requests&lt;/a&gt;.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>ai</category><category>ai-agents</category><category>features</category><category>pulumi-neo</category><category>esc</category></item><item><title>Better CLI Interactions for Agents and Humans</title><link>https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/</link><pubDate>Tue, 19 May 2026 04:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/better-cli-interactions-for-agents-and-humans/index.png" /&gt;
&lt;p&gt;AI agents do a lot of their work through CLIs. They&amp;rsquo;re easier to call than HTTP APIs and they produce predictable output. Over the last few months our own CLI traffic has shifted from mostly people typing commands to people and agents running commands together, often in the same session.&lt;/p&gt;
&lt;p&gt;Today we&amp;rsquo;re shipping a release built for both. The &lt;a href="https://www.pulumi.com/docs/iac/cli/"&gt;Pulumi CLI&lt;/a&gt; is reorganized around three ideas: the right command should be the one you can guess, anything you can do in &lt;a href="https://www.pulumi.com/product/pulumi-cloud/"&gt;Pulumi Cloud&lt;/a&gt; should also be doable from the terminal, and what comes back should be just as readable to an agent as it is to a person.&lt;/p&gt;
&lt;h2 id="designing-for-guessability"&gt;Designing for guessability&lt;/h2&gt;
&lt;p&gt;The bar we set was that both developers and coding agents should be able to guess at the right command for a particular task: &lt;code&gt;pulumi env edit&lt;/code&gt; to modify an environment, &lt;code&gt;pulumi stack get&lt;/code&gt; to see what&amp;rsquo;s going on with a stack, &lt;code&gt;pulumi org member list&lt;/code&gt; to see who&amp;rsquo;s on the team. If we had to explain which command did what, the usability bar hadn&amp;rsquo;t been met.&lt;/p&gt;
&lt;p&gt;Branches in the tree are now singular nouns like &lt;code&gt;stack&lt;/code&gt;, &lt;code&gt;env&lt;/code&gt;, &lt;code&gt;org&lt;/code&gt;, and &lt;code&gt;deployment&lt;/code&gt;. Leaves are now verbs from a canonical vocabulary — &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;new&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt; — and they mean the same thing wherever they&amp;rsquo;re used. &lt;code&gt;edit&lt;/code&gt; always means &lt;em&gt;modify an existing thing&lt;/em&gt;. Wherever the old vocabulary differed, though, the old name still works: &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;rm&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, and &lt;code&gt;open&lt;/code&gt; are all aliased to preserve backward compatibility.&lt;/p&gt;
&lt;p&gt;For the most part, product names have also been replaced with familiar nouns. Users (human or otherwise) don&amp;rsquo;t think in product names; they think in terms of resources, stacks, environments. For example, take &lt;a href="https://www.pulumi.com/esc/"&gt;Pulumi ESC&lt;/a&gt;: the product may be named ESC (and for a while the command was too), but nobody thinks &lt;em&gt;I need to initialize a new ESC&lt;/em&gt; — they think &lt;em&gt;I need to create a new environment&lt;/em&gt;. The command is therefore &lt;code&gt;pulumi env new&lt;/code&gt;, with &lt;code&gt;esc init&lt;/code&gt; preserved as an alias to avoid disrupting anyone&amp;rsquo;s existing workflows.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi env new my-project my-env
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Environment created.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="all-of-pulumi-cloud-in-the-terminal"&gt;All of Pulumi Cloud in the terminal&lt;/h2&gt;
&lt;p&gt;Up to now, most of what you could do with Pulumi Cloud had to be done either in the browser or through direct API calls. Things like reviewing deployments, setting up webhooks, finding non-compliant resources, or managing deployment settings all required you to break out &lt;code&gt;curl&lt;/code&gt; and hit the API docs or open a browser and navigate the Pulumi Cloud console.&lt;/p&gt;
&lt;p&gt;That changes today. Pulumi Cloud is now fully accessible from the command line through the &lt;code&gt;pulumi&lt;/code&gt; CLI, with consistently named nouns and verbs aligned to what you&amp;rsquo;d expect:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;pulumi stack get&lt;/code&gt; returns a complete stack overview, metadata, resource list, and more:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi stack get &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --stack cnunciato/chris.nunciato.org/production &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output json &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s2"&gt;&amp;#34;.resources[].type&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s2"&gt;&amp;#34;aws:s3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3:BucketEventSubscription
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucket:Bucket
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucket:Bucket
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucketPublicAccessBlock:BucketPublicAccessBlock
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucketWebsiteConfiguration:BucketWebsiteConfiguration
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucketOwnershipControls:BucketOwnershipControls
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucketNotification:BucketNotification
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; with other stack-related commands like &lt;code&gt;pulumi stack history get events&lt;/code&gt;, &lt;code&gt;pulumi stack drift list&lt;/code&gt;, &lt;code&gt;pulumi stack schedule new&lt;/code&gt;, and &lt;code&gt;pulumi stack webhook new&lt;/code&gt; alongside it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Organizational commands like &lt;code&gt;pulumi org member list&lt;/code&gt;, &lt;code&gt;pulumi org role list&lt;/code&gt;, &lt;code&gt;pulumi org usage get&lt;/code&gt;, and &lt;code&gt;pulumi org audit-log export&lt;/code&gt; can help you dig into the details when you need to as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deployment-related commands like &lt;code&gt;pulumi deployment list&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;, and &lt;code&gt;cancel&lt;/code&gt; let you see what&amp;rsquo;s running, dive into what happened, and take action without having to leave the terminal.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi deployment list &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --stack cnunciato/chris.nunciato.org/production &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output table
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌──────────────────────────────────────┬───────────┬─────────┬───────────┬──────────────┬─────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ID │ OPERATION │ VERSION │ STATUS │ INITIATED BY │ MODIFIED │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├──────────────────────────────────────┼───────────┼─────────┼───────────┼──────────────┼─────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 83e44b8c-643c-4e9f-9f36-0c6a81d9db2e │ update │ &lt;span class="m"&gt;140&lt;/span&gt; │ running │ cnunciato │ 2026-05-17 21:26:37.340 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 52a37cbe-b7fd-4027-8e0f-7b4785ab12e8 │ update │ &lt;span class="m"&gt;139&lt;/span&gt; │ succeeded │ cnunciato │ 2026-05-16 23:36:07.999 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 94e04525-b3a4-42b5-9987-e344018a3324 │ preview │ &lt;span class="m"&gt;138&lt;/span&gt; │ succeeded │ cnunciato │ 2026-05-16 23:29:19.709 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────────────────────────────────────┴───────────┴─────────┴───────────┴──────────────┴─────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;And when you need to query across managed (and even unmanaged) resources, &lt;code&gt;pulumi insights resource search&lt;/code&gt; and &lt;code&gt;get&lt;/code&gt; can help you find what you&amp;rsquo;re looking for quickly:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi insights resource search &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --query &lt;span class="s1"&gt;&amp;#39;type:aws:s3/bucket:Bucket org:cnunciato project:photomap stack:dev&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output table
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌──────────────────────────────────────────────────────────────────────────┬──────────────────────┬───────┬──────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ URN │ TYPE │ STACK │ MODIFIED │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├──────────────────────────────────────────────────────────────────────────┼──────────────────────┼───────┼──────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ urn:pulumi:dev::photomap::aws:apigateway:x:API&lt;span class="nv"&gt;$aws&lt;/span&gt;:s3/bucket:Bucket::api │ aws:s3/bucket:Bucket │ dev │ 2020-10-31T00:39:47.926Z │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ urn:pulumi:dev::photomap::aws:s3/bucket:Bucket::images │ aws:s3/bucket:Bucket │ dev │ 2020-10-31T00:39:47.926Z │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────────────────────────────────────────────────────────────────────────┴──────────────────────┴───────┴──────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Showing &lt;span class="m"&gt;2&lt;/span&gt; of &lt;span class="m"&gt;2&lt;/span&gt; resources.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flags and output formats are consistent across commands (&lt;code&gt;--output table&lt;/code&gt;, &lt;code&gt;json&lt;/code&gt;), as are the shapes of cross-cutting features like webhooks. If you&amp;rsquo;ve used &lt;code&gt;pulumi stack webhook&lt;/code&gt;, for example, you already know how to use &lt;code&gt;pulumi env webhook&lt;/code&gt; and &lt;code&gt;pulumi org webhook&lt;/code&gt;, and so on.&lt;/p&gt;
&lt;h2 id="direct-access-to-the-pulumi-cloud-api"&gt;Direct access to the Pulumi Cloud API&lt;/h2&gt;
&lt;p&gt;For any features of Pulumi Cloud that don&amp;rsquo;t yet have their own commands, you&amp;rsquo;ve also got &lt;a href="https://www.pulumi.com/docs/iac/cli/api/"&gt;&lt;code&gt;pulumi api&lt;/code&gt;&lt;/a&gt;. It&amp;rsquo;s a &lt;code&gt;gh api&lt;/code&gt;-inspired command designed to give you direct access to the full REST API, without having to manage separate access tokens, auth settings, or request/response payloads. Everything is handled for you through your authenticated &lt;code&gt;pulumi&lt;/code&gt; CLI.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s even &lt;code&gt;pulumi api list&lt;/code&gt;, which enumerates every single endpoint that&amp;rsquo;s exposed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi api list
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌───────────────┬────────┬───────────────────────────────────────┬──────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ TAG │ METHOD │ PATH │ SUMMARY │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├───────────────┼────────┼───────────────────────────────────────┼──────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ GET │ /api/orgs/&lt;span class="o"&gt;{&lt;/span&gt;orgName&lt;span class="o"&gt;}&lt;/span&gt;/tokens │ ListOrgTokens │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ POST │ /api/orgs/&lt;span class="o"&gt;{&lt;/span&gt;orgName&lt;span class="o"&gt;}&lt;/span&gt;/tokens │ CreateOrgToken │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ DELETE │ /api/orgs/&lt;span class="o"&gt;{&lt;/span&gt;orgName&lt;span class="o"&gt;}&lt;/span&gt;/tokens/&lt;span class="o"&gt;{&lt;/span&gt;tokenId&lt;span class="o"&gt;}&lt;/span&gt; │ DeleteOrgToken │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ GET │ /api/user/tokens │ ListPersonalTokens │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ POST │ /api/user/tokens │ CreatePersonalToken │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ DELETE │ /api/user/tokens/&lt;span class="o"&gt;{&lt;/span&gt;tokenId&lt;span class="o"&gt;}&lt;/span&gt; │ DeletePersonalToken │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;537&lt;/span&gt; operations. Pass --output&lt;span class="o"&gt;=&lt;/span&gt;json &lt;span class="k"&gt;for&lt;/span&gt; a stable, scriptable contract.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To get the details about a particular API, use &lt;code&gt;pulumi api describe&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi api describe &lt;span class="s1"&gt;&amp;#39;DELETE /api/user/tokens/{tokenId}&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;# or DeletePersonalToken&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DELETE /api/user/tokens/&lt;span class="o"&gt;{&lt;/span&gt;tokenId&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Tag: AccessTokens
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Operation: DeletePersonalToken
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DeletePersonalToken
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Permanently deletes a personal access token by its identifier. The token is immediately
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;invalidated and can no longer be used &lt;span class="k"&gt;for&lt;/span&gt; authentication. Returns &lt;span class="m"&gt;204&lt;/span&gt; on success or &lt;span class="m"&gt;404&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; the token does not exist.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Parameters:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;path&lt;span class="o"&gt;]&lt;/span&gt; tokenId* &lt;span class="o"&gt;(&lt;/span&gt;string&lt;span class="o"&gt;)&lt;/span&gt; — The access token identifier
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All requests are made through your authenticated &lt;code&gt;pulumi&lt;/code&gt; CLI:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi login
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Logged in to pulumi.com as cnunciato.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi whoami
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cnunciato
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi api /api/user/tokens/2cf15c7d-afad-458f-ace0-fc7ff0512b10 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --method DELETE &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Token deleted.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Token deleted.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Newly published endpoints are available through &lt;code&gt;pulumi api&lt;/code&gt; immediately, so you don&amp;rsquo;t have to wait for a new CLI release before you can start using them. See the &lt;a href="https://www.pulumi.com/docs/reference/cloud-rest-api/"&gt;Pulumi Cloud REST API documentation&lt;/a&gt; to learn more.&lt;/p&gt;
&lt;h2 id="finding-templates-in-the-pulumi-cloud-registry"&gt;Finding templates in the Pulumi Cloud Registry&lt;/h2&gt;
&lt;p&gt;Finding out which templates are available to you through your Pulumi organization used to mean having to navigate to the &lt;a href="https://www.pulumi.com/registry/"&gt;Pulumi Cloud Registry&lt;/a&gt; and start searching. The new &lt;code&gt;pulumi template&lt;/code&gt; commands make this easier by letting you ask for what&amp;rsquo;s available right from the shell, either by fetching the full list or filtering with the &lt;code&gt;--name&lt;/code&gt; or &lt;code&gt;--search&lt;/code&gt; params:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi template list --search &lt;span class="s2"&gt;&amp;#34;container typescript&amp;#34;&lt;/span&gt; --org cnunciato
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌─────────────────────────────────────────────┬────────┬────────────┬────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ Name │ Source │ Language │ Visibility │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─────────────────────────────────────────────┼────────┼────────────┼────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ pulumi/templates/container-aws-typescript │ github │ typescript │ public │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ pulumi/templates/container-azure-typescript │ github │ typescript │ public │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ pulumi/templates/container-gcp-typescript │ github │ typescript │ public │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└─────────────────────────────────────────────┴────────┴────────────┴────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is especially useful when you&amp;rsquo;re working with an agent because it helps the agent discover your org&amp;rsquo;s approved templates without having to name them. Start with a prompt that tells the agent what you want to build, and let the agent find the right template for you.&lt;/p&gt;
&lt;h2 id="agent-friendly-markdown-docs-for-providers-and-components"&gt;Agent-friendly Markdown docs for providers and components&lt;/h2&gt;
&lt;p&gt;Both humans and agents need to be able to understand what&amp;rsquo;s inside a Pulumi package before they can use it. And while the &lt;a href="https://www.pulumi.com/registry/"&gt;Registry&lt;/a&gt; is an excellent resource for that, it was mainly designed to deliver HTML — a human-friendly format that agents can certainly use, but that&amp;rsquo;s much more verbose than they actually need.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;pulumi api&lt;/code&gt;, agents can fetch the details about a package from the Registry directly and get back those details either in &lt;code&gt;markdown&lt;/code&gt; or &lt;code&gt;json&lt;/code&gt;, whichever works best, filtering on properties like language where applicable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi api &lt;span class="s2"&gt;&amp;#34;/api/registry/packages/pulumi/pulumi/random/versions/4.19.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;random&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;publisher&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;pulumi&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;publisherDisplayName&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;Pulumi&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;source&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;pulumi&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;4.19.1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;A Pulumi package to safely use randomness in Pulumi programs.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;repoUrl&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;https://github.com/pulumi/pulumi-random&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi api &lt;span class="s2"&gt;&amp;#34;/api/registry/packages/pulumi/pulumi/random/versions/4.19.1/docs/random%3Aindex%2FrandomPassword%3ARandomPassword&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output markdown
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# RandomPassword&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;resource &lt;span class="sb"&gt;`&lt;/span&gt;random:index/randomPassword:RandomPassword&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;## Example Usage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;package main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Resources are individually addressable using their URL-encoded Pulumi type tokens — e.g., &lt;code&gt;random:index/randomPassword:RandomPassword&lt;/code&gt; — and API endpoints are configured to deliver Markdown when agents ask for it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl &lt;span class="s2"&gt;&amp;#34;https://api.pulumi.com/api/registry/packages/pulumi/pulumi/random/versions/latest/readme?lang=python&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Accept: text/markdown&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Installation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;The Random provider is available as a package in all Pulumi languages:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Even compared to JSON (which is itself a significant improvement over HTML), Markdown is a much more token-efficient format for agents to work with:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;JSON&lt;/th&gt;
&lt;th&gt;Markdown&lt;/th&gt;
&lt;th&gt;Tokens saved&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;random&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/readme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10.68 KB&lt;/td&gt;
&lt;td&gt;6.04 KB&lt;/td&gt;
&lt;td&gt;43%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;aws&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/readme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4.22 KB&lt;/td&gt;
&lt;td&gt;2.54 KB&lt;/td&gt;
&lt;td&gt;40%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;aws&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/nav?depth=full&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;204 KB&lt;/td&gt;
&lt;td&gt;170 KB&lt;/td&gt;
&lt;td&gt;17%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;aws&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/docs/{resource type token}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;15.24 KB&lt;/td&gt;
&lt;td&gt;11.28 KB&lt;/td&gt;
&lt;td&gt;26%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;azure-native&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/docs/{resource type token}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;48.13 KB&lt;/td&gt;
&lt;td&gt;30.37 KB&lt;/td&gt;
&lt;td&gt;37%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;aws&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/docs/{function type token}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2.40 KB&lt;/td&gt;
&lt;td&gt;1.46 KB&lt;/td&gt;
&lt;td&gt;39%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Learn more about our Registry endpoints in the &lt;a href="https://www.pulumi.com/docs/reference/cloud-rest-api/registry-preview/"&gt;REST API docs&lt;/a&gt;. (Or just ask your agent!)&lt;/p&gt;
&lt;h2 id="new-to-the-cli-pulumi-neo"&gt;New to the CLI: Pulumi Neo&lt;/h2&gt;
&lt;p&gt;When we launched &lt;a href="https://www.pulumi.com/neo/"&gt;Pulumi Neo&lt;/a&gt; last year, the only way to use it was in the Pulumi Cloud Console. But while there&amp;rsquo;s a ton you can do with Neo in the browser, if you&amp;rsquo;re an engineer already living in the terminal, chances are that eventually you&amp;rsquo;re going to wish you had Neo right in the CLI along with you.&lt;/p&gt;
&lt;p&gt;Now you do. Running &lt;code&gt;pulumi neo&lt;/code&gt; with or without a prompt launches a Pulumi Cloud-connected session that gives Neo access to your local environment just like any other coding agent. Use it on its own to scaffold a new project, understand an existing codebase, or debug a failing deployment — or pull it into an active session with the coding agent you&amp;rsquo;re already using. Either way, it stays in the shell you&amp;rsquo;re already working in.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll cover Neo in the CLI in more detail &lt;a href="https://www.pulumi.com/blog/pulumi-neo-cli/"&gt;later this week&lt;/a&gt;. In the meantime, here&amp;rsquo;s a peek:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/neo-cli.png" alt="Running Neo in the Pulumi CLI"&gt;&lt;/p&gt;
&lt;h2 id="smaller-changes-that-add-up"&gt;Smaller changes that add up&lt;/h2&gt;
&lt;p&gt;A long list of smaller changes also runs through this release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The core loop now speaks JSON end to end, with &lt;code&gt;pulumi up&lt;/code&gt;, &lt;code&gt;pulumi destroy&lt;/code&gt;, and &lt;code&gt;pulumi import&lt;/code&gt; all emitting structured JSON output when called with &lt;code&gt;--output json&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Streams now behave the way scripts expect them to, with data on stdout, progress and diagnostics on stderr.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Exit codes are more consistent across the board. Every failure mode — auth, resource, policy, missing stack, cancellation, timeout, and others — has its own exit code, so agents can branch on the actual cause instead of having to interpret output. The &lt;a href="https://www.pulumi.com/docs/iac/cli/exit-codes/"&gt;full table&lt;/a&gt; is in the docs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Help text explains &lt;em&gt;why&lt;/em&gt; a command exists, not just what it does, and includes at least one concrete example. Examples in &lt;code&gt;--help&lt;/code&gt; are one of the most effective ways to improve LLM accuracy on first-try invocations — and it turns out they&amp;rsquo;re pretty handy for humans, too.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="a-sneak-peek-at-a-new-command"&gt;A sneak peek at a new command&lt;/h2&gt;
&lt;p&gt;Later this week, you&amp;rsquo;ll get a closer look at &lt;code&gt;pulumi do&lt;/code&gt;, a new top-level command that enables direct resource operations like create, read, update, delete, and list across every Pulumi-supported cloud provider and resource, all in one command. A simple example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws getAvailabilityZones
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;groupNames&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2-zg-1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;names&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2a&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2b&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2c&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2d&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;region&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;zoneIds&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;usw2-az2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;usw2-az1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;usw2-az3&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;usw2-az4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It might look like that&amp;rsquo;s calling the AWS CLI, but it&amp;rsquo;s not — it&amp;rsquo;s using &lt;a href="https://www.pulumi.com/registry/packages/aws/api-docs/getavailabilityzones/"&gt;the same AWS provider function&lt;/a&gt; a full Pulumi program would use, only without the program, and invoked directly from the CLI.&lt;/p&gt;
&lt;p&gt;More on how it works, and what you can do with it, in the days ahead.&lt;/p&gt;
&lt;h2 id="try-it-yourself"&gt;Try it yourself&lt;/h2&gt;
&lt;p&gt;A lot of what makes a developer tool worth using is in the details, and most of what&amp;rsquo;s in &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;this release&lt;/a&gt; is exactly that, across the whole CLI, with humans and agents in mind.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;d love for you to &lt;a href="https://www.pulumi.com/docs/get-started/download-install/"&gt;grab the latest release&lt;/a&gt; and give it a try. Tell us what&amp;rsquo;s now easy, what&amp;rsquo;s still hard, and what to fix next on &lt;a href="https://github.com/pulumi/pulumi/issues"&gt;GitHub&lt;/a&gt; or in the &lt;a href="https://slack.pulumi.com/"&gt;community Slack&lt;/a&gt;. The fastest way the CLI gets better is feedback from the humans and agents who live in it.&lt;/p&gt;</description><author>Michael Fallihee</author><author>Christian Nunciato</author><category>features</category><category>pulumi-cli</category><category>ai-agents</category><category>product-launches</category></item><item><title>The Agentic Infrastructure Era</title><link>https://www.pulumi.com/blog/the-agentic-infrastructure-era/</link><pubDate>Tue, 19 May 2026 03:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/the-agentic-infrastructure-era/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/the-agentic-infrastructure-era/index.png" /&gt;
&lt;p&gt;The first frontier agents excelled at was coding. The reason is evident: we have billions of lines of self-documenting code available on the internet for the LLMs to learn from. We can measure their performance on coding thanks to linters, type checkers, compilers, and test suites. The most advanced agentic systems to hit product/market fit have been coding-oriented, and it has resulted in an intense velocity increase in how much and how fast code we can write.&lt;/p&gt;
&lt;p&gt;But as the AI tsunami whips up reams of code, what happens to it becomes just as critical. As an industry, we&amp;rsquo;ve moved beyond just coding to engineering, which includes documentation, tests, automation, and, yes, managing the very infrastructure our applications need to run. The deeper into production you go, however, the less good agents naturally are at helping. At Pulumi, we live and breathe infrastructure, and have seen this firsthand. But we&amp;rsquo;ve also been hard at work building the platform this new era runs on. In this post, I&amp;rsquo;ll share our point of view, what we&amp;rsquo;ve built, what we&amp;rsquo;re launching today, and why all infrastructure is about to be agentic.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/product/neo/"&gt;See Pulumi Neo in action →&lt;/a&gt; Neo is the agent at the center of everything below: it previews changes, checks them against policy, and opens PRs for your review.&lt;/p&gt;
&lt;h2 id="llms-are-natural-coders"&gt;LLMs are natural coders&lt;/h2&gt;
&lt;p&gt;It is remarkable to look back and note that frontier models, less than two years ago, in August 2024, scored just 33% on SWE-bench Verified. Present-day models score 86%, which represents a 4x reduction in the errors models will make when coding. This enables models to solve increasingly difficult coding problems, and humans can lean more heavily on them to offload tasks. Anthropic&amp;rsquo;s new Mythos model scores 94% and, although it isn&amp;rsquo;t generally available at the time of this article, there&amp;rsquo;s no question we&amp;rsquo;ll close in on 95% by the end of 2026. That is another 2.3x reduction in error rates. This very naturally puts us onto the last mile of fully agentic coding.&lt;/p&gt;
&lt;p&gt;This has been the result of code being highly in-distribution combined with the relentless pursuit of solving coding problems from the frontier labs, especially with Anthropic&amp;rsquo;s Claude Code, but now with OpenAI&amp;rsquo;s Codex, driving a tight feedback loop that turns into an improvement flywheel.&lt;/p&gt;
&lt;p&gt;Given that LLMs are natural coders, most of us simply assumed that the breakout success we&amp;rsquo;ve seen with agents for coding would automatically translate into new problem domains. And for sure, we have seen some success. But perhaps not as much as we&amp;rsquo;d like. Not all problem domains are documented equally well so that the models can naturally learn about them.&lt;/p&gt;
&lt;p&gt;Andrej Karpathy noted nearly a year ago that, &amp;ldquo;Building a modern app is a bit like assembling IKEA furniture,&amp;rdquo; observing that, though writing the code was easy, fun, and fast, the next mile of actually getting the application running in production entailed many things the LLM wasn&amp;rsquo;t naturally good at, including &amp;ldquo;services, API keys, configurations, dev/prod deployments.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;At the same time, we&amp;rsquo;re seeing something magical happen here at Pulumi: LLMs are now doing over 20% of the infrastructure deployments, up from virtually zero a year ago. We expect this to grow to over 50% before the end of this year and well beyond afterwards.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/the-agentic-infrastructure-era/agentic-share-circular-light.png" alt="Over 20% of all Pulumi operations are now being handled by LLMs."&gt;&lt;/p&gt;
&lt;p&gt;The agentic infrastructure era is here. Today we&amp;rsquo;re announcing several new platform capabilities to accelerate it further.&lt;/p&gt;
&lt;p&gt;Before getting to what&amp;rsquo;s new, however, why are we seeing this happening in reality?&lt;/p&gt;
&lt;h2 id="turning-infrastructure-problems-into-coding-problems"&gt;Turning infrastructure problems into coding problems&lt;/h2&gt;
&lt;p&gt;We began our journey with our open-source infrastructure-as-code project nearly ten years ago. Having spent much of my career working on programming languages and compilers, I had a strong conviction that the right substrate for infrastructure was the languages developers already knew and loved, not yet another DSL and certainly not piles of YAML. So we focused first on great ergonomics for humans, and for us, that meant letting you use programming languages, tools, and ecosystems that humans already know and love. Languages like Python, TypeScript, Go, C#, Java, and more. Infrastructure as code also, importantly, comes with guardrails to make infrastructure deployments dependable, reviewable, and auditable. Over time we&amp;rsquo;ve built out an entire platform with security, compliance, and governance capabilities.&lt;/p&gt;
&lt;p&gt;One way of thinking about this is we modeled the realm of cloud infrastructure inside the realm of programming languages: cloud resources become objects, configurations are just variables, dependencies between resources are just references, standard blueprints become classes. Doing so turns the cloud into something that is suddenly programmable, and allows us to apply real software engineering patterns and practices to infrastructure.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the twist we&amp;rsquo;ve realized this past year. It is a happy accident that the combination of this plus the verifiability of every change is the exact combination that empowers agents to do infrastructure. LLMs are natural coders. By mapping infrastructure space in code space, agents can do what they&amp;rsquo;re great at – code – and the infrastructure as code engine is the link that maps those code edits back down into infrastructure space. And as the SWE-bench curve plays out, every domain expressed in code rides it. Infrastructure, thanks to the bet we made nine years ago, is now one of them.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t just about volume of in-distribution code. Most production infrastructure code lives in private repositories. In contrast, public Python and TypeScript include vast amounts of genuinely production-grade open source, demonstrating real patterns at scale. Public infrastructure DSL corpora skew heavily toward tutorial-grade content that doesn&amp;rsquo;t scale. By modeling infrastructure in real languages, Pulumi inherits at-scale in-distribution directly. Patterns in Python or TypeScript generalize from what the model has practiced, while DSL patterns are idiosyncratic by definition and don&amp;rsquo;t compound the same way. Code can express everything an engineer can do, which is exactly why models trained on it have become prolific engineers.&lt;/p&gt;
&lt;p&gt;What does this look like in practice? For example, an agent can define reusable infrastructure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_coreweave&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;coreweave&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_nvidia_aicr&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;aicr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TrainingCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ComponentResource&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;A reusable training cluster resource.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;kubeconfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;training:Cluster&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;coreweave&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KubernetesCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-k8s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# gb200/b200/h100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aicr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClusterStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-aicr&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;kubeconfig&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kubeconfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;training&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;platform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;kubeflow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And then flexibly consume it – all using languages, like Python, it is already fluent in:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;infra&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TrainingCluster&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;orchestration&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RLFleet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Spin up an RL stack with 1 learner and 8 rollout workers.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;learner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TrainingCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;learner&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;gb200&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rollouts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TrainingCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rollout-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;b200&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;fleet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RLFleet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ppo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;learner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;learner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rollouts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;login&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fleet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Beyond just being in-distribution, infrastructure as code also gives us a critical piece: the ability to diff changes at the infrastructure layer. Just as we wouldn&amp;rsquo;t vibe code without git showing us the source changes, we shouldn&amp;rsquo;t vibe infrastructure without a tool that shows what it will do before it does it, and what it has already done in the past. It&amp;rsquo;s like git diff for your infrastructure.&lt;/p&gt;
&lt;p&gt;The combination of languages, type systems, linting, testing, and infrastructure diffs gives agents enough of what they need to create a fully closed, verifiable, self-correcting loop. Verifiability is the thing that ultimately matters. Every action an agent takes can be previewed, policy-checked, reviewed, and audited. By humans, by other agents, by CI/CD automation. Guardrails guide the agent and verifiability proves the end result.&lt;/p&gt;
&lt;p&gt;When I say &amp;ldquo;infrastructure&amp;rdquo; by the way, I mean something quite broad. It includes public cloud hyperscalers, of course, like AWS, Azure, Google Cloud, and CoreWeave. It includes cloud native technologies like Kubernetes and Helm. It also includes private clouds powered by VMware and other data center technologies. It includes broad cloud platforms like Cloudflare. But, subtly, also any hosted managed infrastructure service, such as Snowflake, MongoDB, Databricks, and more. And increasingly, the observability, security, and operational tooling that wraps everything else, like Datadog, Sentry, PagerDuty, and other systems that give agents the context to reason about what&amp;rsquo;s actually happening in production. We support thousands of providers with a consistent programming model and agents are increasingly writing those too.&lt;/p&gt;
&lt;h2 id="what-were-shipping-today"&gt;What we&amp;rsquo;re shipping today&lt;/h2&gt;
&lt;p&gt;The foundation of expressing infrastructure as code, combined with verifiable changes, makes a 100% agentic infrastructure future even conceivable. But we still have work to realize this vision.&lt;/p&gt;
&lt;h3 id="meeting-agents-where-they-work-the-cli"&gt;Meeting agents where they work (the CLI)&lt;/h3&gt;
&lt;p&gt;We know real code is the right substrate for agentic infrastructure – but we also know agents want to start with the smallest possible commitment and progressively level up. So we&amp;rsquo;ve designed the Pulumi experience as a progression: an agent should be able to sign up, run its first command, and grow into a full infrastructure as code workflow without ever hitting a wall or manual intervention. Here&amp;rsquo;s what we&amp;rsquo;re launching today to make that journey work end-to-end:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/docs/administration/organizations-teams/agent-accounts/"&gt;Agent accounts&lt;/a&gt;.&lt;/strong&gt; Now agents can use free, ephemeral Pulumi Cloud accounts straight from Claude Code, Codex, OpenCode, Copilot, Cursor, and others. This lets an agent do anything a human could with the Pulumi product without a manual signup step, removing friction while letting agents benefit from robust infrastructure management. A human can claim that account at any time to make it permanent and to share with their team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/pulumi"&gt;One-command execution&lt;/a&gt;.&lt;/strong&gt; Today an agent needs to know how to find, download, and install Pulumi, and manage subsequent versioning and upgrades. Anything that adds friction is discouraging to an agent. We now have an npm package that enables &lt;code&gt;npx pulumi &amp;lt;anything&amp;gt;&lt;/code&gt;-style commands so agents can run any Pulumi command anywhere without needing to worry about installation or version pinning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/pulumi-do-direct-resource-operations/"&gt;Imperative infrastructure operations&lt;/a&gt;.&lt;/strong&gt; The new &lt;code&gt;pulumi do&lt;/code&gt; command enables direct create, read, update, delete, list, and API operations with a single command. For example, &lt;code&gt;pulumi do create eks:Cluster&lt;/code&gt; spins up an AWS EKS cluster with built-in best practices, and &lt;code&gt;pulumi do update cloudflare:r2:Bucket --tags '{ &amp;quot;Foo&amp;quot;: &amp;quot;Bar&amp;quot; }'&lt;/code&gt; updates a bucket&amp;rsquo;s tags. All thousands of providers and hundreds of thousands of resource types in the Pulumi ecosystem are supported across clouds. As the complexity of your scenario outgrows singular commands, it is easy to eject out into a full-blown infrastructure-as-code project.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/"&gt;Pulumi Cloud in the CLI&lt;/a&gt;.&lt;/strong&gt; Over the years, we&amp;rsquo;ve added tons of great capabilities to Pulumi Cloud – things like change history, time-to-live stacks, drift detection, resource discovery and search, private registries, IDP, audit logs, secrets management, team-wide policy enforcement – but didn&amp;rsquo;t add the respective ergonomic commands to the CLI. These are the sort of features that matter at scale. Now it&amp;rsquo;s all there in your terminal where agents can use them. Over 30 new commands, you can think of this as the equivalent of the &lt;code&gt;gh&lt;/code&gt; CLI which agents really like.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/"&gt;&lt;strong&gt;Read the blog&lt;/strong&gt;: Better CLI Interactions for Agents and Humans →&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="neo-everywhere-you-work"&gt;Neo, everywhere you work&lt;/h3&gt;
&lt;p&gt;Once an agent (or a team) has graduated through these capabilities, what comes next is asynchronous infrastructure work and, increasingly, autonomy. That&amp;rsquo;s where Neo comes in: Pulumi&amp;rsquo;s own infrastructure agent, now upgraded with the surfaces, integrations, and cadences teams actually need to run agentic infrastructure in production. We are shipping:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/pulumi-neo-cli/"&gt;Neo in the CLI&lt;/a&gt;.&lt;/strong&gt; The new &lt;code&gt;pulumi neo&lt;/code&gt; command lets you run the same agent that is already in Pulumi Cloud. It even shares the same agentic loop and uses a sophisticated architecture where the agent workstation is your local computer, allowing it to more seamlessly access source context and tools. This allows you to do agentic infrastructure wherever you prefer: Neo in the cloud for asynchronous, autonomous tasks, or your workstation for more intensive deep-dive paired sessions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/neo-github-slack/"&gt;Neo GitHub and Slack Apps&lt;/a&gt;.&lt;/strong&gt; Now you can @-mention Neo from GitHub pull requests, and/or straight from Slack, to kick off agentic infrastructure workflows wherever it is most convenient, complete with whatever guardrails you&amp;rsquo;ve configured already.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/neo-integrations/"&gt;Neo Integration Catalog&lt;/a&gt;.&lt;/strong&gt; A new integration catalog lets you configure connectors to other systems that bring valuable infrastructure management context, including Atlassian, Datadog, Honeycomb, Linear, PagerDuty, and Supabase. This lets you tap into additional planning, specification, observability, and live site incident data, expanding what agents can do on Days 0, 1, and especially 2.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/neo-automations/"&gt;Scheduled Tasks and Read-Only Sessions&lt;/a&gt;.&lt;/strong&gt; Now you can automate recurring infrastructure tasks, including confining Neo to read-only operations for extra safety. This opens up scenarios like reporting on infrastructure patterns weekly, automatically cleaning up waste in your dev accounts daily, or scheduled maintenance and upgrades.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/blog/10-more-things-you-can-do-with-neo/"&gt;&lt;strong&gt;Read the blog&lt;/strong&gt;: 10 More Things You Can Do with Pulumi Neo →&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="partnering-with-the-frontier-of-ai-infrastructure"&gt;Partnering with the frontier of AI infrastructure&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;re investing in deep partnerships with the companies building the frontier of AI infrastructure, and are shipping two new partner providers in close collaboration with the teams behind them:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/registry/packages/coreweave/"&gt;CoreWeave provider&lt;/a&gt;.&lt;/strong&gt; This new provider brings the full power of the CoreWeave platform, the leader in GPU infrastructure, to help teams provision AI workloads with ease. This includes support for all of the CoreWeave services including CoreWeave Kubernetes Service (CKS) and includes several examples and templates out of the box for training and inference architectures written in AI-native languages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/pulumi-labs/pulumi-nvidia-aicr"&gt;NVIDIA AI Cluster Runtime (AICR) provider&lt;/a&gt;.&lt;/strong&gt; This new provider delivers fully functional NVIDIA software stacks atop the underlying cloud provider&amp;rsquo;s GPU infrastructure. This packages out-of-the-box components like NVIDIA GPU Operator, Kubeflow, NIM Operator, and dozens more otherwise tricky-to-configure cluster components. We&amp;rsquo;re excited to showcase the new AICR provider in tandem with our new CoreWeave provider: you can now spin up a CKS cluster and configure it with AICR in one program.&lt;/p&gt;
&lt;h3 id="educating-and-measuring-agentic-infrastructure-intelligence"&gt;Educating and measuring agentic infrastructure intelligence&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ve also invested in making Pulumi maximally legible to agents, because the best tools only matter if agents can find them, read them, and know which one to reach for and when:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/#agent-friendly-markdown-docs-for-providers-and-components"&gt;Agent-friendly docs&lt;/a&gt;.&lt;/strong&gt; We now serve our docs website in markdown to agents and did a pass over our documentation and CLI text to ensure it&amp;rsquo;s maximally useful to agents.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/"&gt;Agent-friendly CLI ergonomics&lt;/a&gt;.&lt;/strong&gt; We have added &lt;code&gt;--json&lt;/code&gt; and structured errors across the CLI to help agents parse and react to outputs appropriately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/docs/ai/skills/"&gt;New skills&lt;/a&gt;.&lt;/strong&gt; We&amp;rsquo;ve done a pass over our skills and added a new uber-skill that describes how an agent should leverage the full suite of capabilities we now offer, from Level 0 (agent accounts), to Level 1 (&lt;code&gt;pulumi do&lt;/code&gt;), to Level 2 (full IaC and &lt;code&gt;pulumi up&lt;/code&gt;), to Level 3 (Pulumi Cloud governance and full autonomy with Neo), and beyond. It&amp;rsquo;s handy for humans too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;InfraBench.&lt;/strong&gt; We have created a new benchmark to measure how well an agent performs on a wide array of representative infrastructure tasks. This is the infrastructure equivalent to SWE-bench and lets us measure stock agents, agents plus the new tools and skills, and Neo, and how they&amp;rsquo;re improving over time. Although we are still hard at work on building out the comprehensive suite, and will keep it internally for now, we will begin publishing our progress against InfraBench as we continue tackling new problems and improving agent performance.&lt;/p&gt;
&lt;h2 id="what-comes-next"&gt;What comes next&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;re primarily focused on two pillars as we go forward:&lt;/p&gt;
&lt;p&gt;First, we are making &lt;a href="https://www.pulumi.com/what-is/what-is-agentic-infrastructure/"&gt;agentic infrastructure&lt;/a&gt; a reality with increasingly autonomous workflows. The pace and scale of infrastructure in an AI era are beyond anything we&amp;rsquo;ve seen before, and we need to ensure infrastructure doesn&amp;rsquo;t become the bottleneck to velocity. We will be shipping steady improvements that help agents score better on InfraBench as a measure of their abilities. This will begin with new building blocks and in-context improvements, but we&amp;rsquo;re really excited that every improvement the frontier labs ship in general-purpose coding ability is automatically an improvement in agentic infrastructure on Pulumi, at zero cost to us or to our users. The result is that Pulumi-equipped agents will consistently and measurably outperform raw agents on real infrastructure work, and that gap will compound as the substrate and the models both improve.&lt;/p&gt;
&lt;p&gt;Next, a world in which agents are provisioning, updating, monitoring, and managing all of our infrastructure changes the human/agent/infrastructure interface greatly. We need better change management, policy enforcement, and observability tools. Going from a single human doing a single infrastructure task at a time, to a single agent doing that task, to teams of agents doing lots of autonomous infrastructure tasks at once, will reveal new bottlenecks needed to fully govern your infrastructure. We have a lot of those facilities in Pulumi Cloud already but we will continue pushing here to improve them and ensure they scale up as fast as they need to. This is the layer that matters even as agents themselves get great at infrastructure. The smartest agent in the world still needs guardrails, audit trails, and policy enforcement to be trusted with production systems at scale, and that layer gets more valuable as agents get more capable, not less.&lt;/p&gt;
&lt;p&gt;The combination of these two things will lead to a world where agents are able to manage more infrastructure, and to do so with increasing autonomy, while human operators retain full visibility, understanding, and control over what their teams of agents are doing at all times. This is the full engineering loop applied to infrastructure. Not just code generation, but design, review, deployment, and operation, with agents and humans collaborating across every step.&lt;/p&gt;
&lt;h2 id="its-a-new-era-and-were-just-getting-started"&gt;It&amp;rsquo;s a new era, and we&amp;rsquo;re just getting started&lt;/h2&gt;
&lt;p&gt;It was remarkable to see in practice and at scale that what&amp;rsquo;s good for humans is good for agents: ergonomic infrastructure as code. We&amp;rsquo;ve seen every point along the spectrum, ranging from Wiz managing 1 million resources and doing 100k daily deployments, to Compostable.ai already living the 100% agentic infrastructure dream, to a frontier lab who grew their infrastructure footprint by 982% in a year, all using infrastructure modeled in true code. All very different scales and teams, but with one thing in common: it was code all the way down.&lt;/p&gt;
&lt;p&gt;Languages and verifiability already provide strong foundations, however, there are still clear areas we need to improve, beginning with making the full suite of infrastructure automation, security, and governance tools more accessible to agents. That&amp;rsquo;s what today is all about. To deep dive on details of &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;the launches&lt;/a&gt;, check out the &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/#from-the-blog"&gt;companion blog posts&lt;/a&gt; released today.&lt;/p&gt;
&lt;p&gt;Agentic infrastructure is a super exciting one-way door for our industry. We&amp;rsquo;re pushing hard to take this beyond 20% and toward 100% in the years ahead. This is uniquely enabled by infrastructure as code in languages the models already speak combined with built-in verifiability that makes agentic work automatically safe. There&amp;rsquo;s more to be done, however, today&amp;rsquo;s launch will bend the curve even further upwards. We&amp;rsquo;re still only just getting started.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/install/"&gt;Get started with Pulumi free →&lt;/a&gt; Install the CLI and provision your first agentic-ready stack in minutes.&lt;/p&gt;
&lt;p&gt;Happy clouding,&lt;/p&gt;
&lt;p&gt;-Joe&lt;/p&gt;</description><author>Joe Duffy</author><category>announcements</category><category>ai</category><category>pulumi-neo</category><category>features</category></item><item><title>Connect Any Git or Mercurial Repo to Pulumi with Custom VCS</title><link>https://www.pulumi.com/blog/connect-any-git-server-to-pulumi-deployments-with-custom-vcs/</link><pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/connect-any-git-server-to-pulumi-deployments-with-custom-vcs/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/connect-any-git-server-to-pulumi-deployments-with-custom-vcs/index.png" /&gt;
&lt;p&gt;Custom VCS is a new Pulumi Cloud integration that connects any Git or Mercurial version control system to &lt;a href="https://www.pulumi.com/docs/deployments/deployments/"&gt;Pulumi Deployments&lt;/a&gt; using webhooks and centrally managed credentials. Pulumi Cloud already has native integrations with &lt;a href="https://www.pulumi.com/docs/integrations/version-control/github-app/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/gitlab/"&gt;GitLab&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/integrations/version-control/azure-devops-integration/"&gt;Azure DevOps&lt;/a&gt;, but if your team uses a self-hosted or third-party VCS, you&amp;rsquo;ve been limited to manually configuring credentials per stack with no webhook-driven automation. Custom VCS closes that gap.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;Many teams run self-hosted or third-party Git servers that Pulumi Cloud doesn&amp;rsquo;t have a native integration for, and some teams still use Mercurial. Until now, their only option was the raw git source approach: embedding credentials directly in each stack&amp;rsquo;s deployment settings, with no way to trigger deployments automatically on push, and no support for Mercurial at all.&lt;/p&gt;
&lt;p&gt;This meant:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No push-to-deploy&lt;/strong&gt;: Every deployment had to be triggered manually or through a separate CI pipeline.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scattered credentials&lt;/strong&gt;: Each stack configured its own credentials independently, with no centralized management.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No org-level integration&lt;/strong&gt;: There was no shared configuration that multiple stacks could reference.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-custom-vcs-works"&gt;How Custom VCS works&lt;/h2&gt;
&lt;p&gt;Custom VCS integrations introduce an org-level integration type that works with any Git or Mercurial server. The setup has three parts:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Credentials through ESC&lt;/strong&gt;: Instead of OAuth flows, you store your VCS credentials (a personal access token, SSH key, or username/password) in a &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; environment. The same credential structure works for both Git and Mercurial. The integration references this environment by name and resolves credentials at deployment time. Multiple stacks can share the same credentials without duplicating secrets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Manual repository registration&lt;/strong&gt;: You add repositories to the integration by name. Pulumi joins the repository name with the integration&amp;rsquo;s base URL to form clone URLs. There&amp;rsquo;s no auto-discovery, so you control exactly which repositories are available.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Webhook-driven deployments&lt;/strong&gt;: Pulumi provides a webhook endpoint and an HMAC shared secret. You configure your VCS server to POST a JSON payload on push events, and Pulumi automatically triggers deployments for matching stacks. The webhook supports branch filtering and optional path filtering.&lt;/p&gt;
&lt;h2 id="whats-supported"&gt;What&amp;rsquo;s supported&lt;/h2&gt;
&lt;p&gt;Custom VCS focuses on the deployment automation use case. Here&amp;rsquo;s how it compares to native integrations:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Native integrations&lt;/th&gt;
&lt;th&gt;Custom VCS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Push-to-deploy&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Path filtering&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PR/MR previews&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit status checks&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PR comments&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review stacks&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Features like PR comments, commit statuses, and review stacks require deep API integration with each VCS platform, so they aren&amp;rsquo;t available with Custom VCS. If your VCS provider is GitHub, GitLab, or Azure DevOps, we recommend using the native integration for the full feature set.&lt;/p&gt;
&lt;h2 id="neo-support"&gt;Neo support&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/ai/"&gt;Neo&lt;/a&gt;, Pulumi&amp;rsquo;s AI assistant, works with Custom VCS integrations for repository operations that don&amp;rsquo;t depend on VCS-specific APIs. Neo can clone and push to Git and Mercurial repositories registered with your Custom VCS integration using the credentials from the integration&amp;rsquo;s ESC environment. Neo cannot open pull requests or create new repositories on Custom VCS servers at this time. Those operations require APIs unique to each VCS platform and are only available through native integrations.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;To set up a Custom VCS integration:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Version control&lt;/strong&gt; in Pulumi Cloud.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Add integration&lt;/strong&gt; and choose &lt;strong&gt;Custom VCS&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Provide a name, base URL, and ESC environment containing your credentials.&lt;/li&gt;
&lt;li&gt;Add your repositories.&lt;/li&gt;
&lt;li&gt;Configure your VCS server to send webhooks to the provided URL.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the full setup guide including webhook payload format, HMAC signing, and credential configuration, see the &lt;a href="https://www.pulumi.com/docs/integrations/version-control/custom-vcs/"&gt;Custom VCS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="learn-more"&gt;Learn more&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/integrations/version-control/custom-vcs/"&gt;Custom VCS documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/deployments/deployments/"&gt;Pulumi Deployments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/deployments/deployments/using/triggers/#push-to-deploy"&gt;Push-to-deploy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Michael Fallihee</author><category>features</category><category>pulumi-cloud</category></item><item><title>Policy Packs Can Now Access Pulumi ESC Environments</title><link>https://www.pulumi.com/blog/policy-packs-can-now-access-pulumi-esc-environments/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/policy-packs-can-now-access-pulumi-esc-environments/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/policy-packs-can-now-access-pulumi-esc-environments/index.png" /&gt;
&lt;p&gt;Policy authors who need external credentials or environment-specific configuration have had to hardcode values or manage them outside of Pulumi. Policy packs can now reference &lt;a href="https://www.pulumi.com/product/secrets-management/"&gt;Pulumi ESC&lt;/a&gt; environments, bringing centralized secrets and configuration management to your policies.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;Pulumi &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-packs/"&gt;policy packs&lt;/a&gt; let you enforce rules across your infrastructure, but some policies need more than just the resource inputs they evaluate. A policy that validates resources against an external compliance API needs an API token. A cost-enforcement policy might need different spending thresholds for development and production environments. An access-control policy might need to reference an internal service registry.&lt;/p&gt;
&lt;p&gt;Until now, these values had to be hardcoded in your policy group configuration or managed through a separate process entirely. This created several problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Security risk&lt;/strong&gt;: Credentials stored in plain text in policy group config&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operational burden&lt;/strong&gt;: Updating a credential meant touching every policy group that used it&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No environment separation&lt;/strong&gt;: The same values applied everywhere, with no way to vary configuration across environments&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="whats-new"&gt;What&amp;rsquo;s new&lt;/h2&gt;
&lt;p&gt;Policy packs can now reference ESC environments, just like &lt;a href="https://www.pulumi.com/docs/esc/environments/syntax/reserved-properties/pulumi-config/"&gt;stacks already do&lt;/a&gt;. When you attach an ESC environment to a policy pack in a policy group, the values from that environment are available to your policies at runtime — whether you&amp;rsquo;re running preventative or audit policies.&lt;/p&gt;
&lt;p&gt;This means your policy packs can use ESC for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Secrets&lt;/strong&gt;: API tokens, service credentials, and other sensitive values managed through ESC&amp;rsquo;s secrets management, including dynamic credentials from providers like AWS, Azure, and GCP&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration&lt;/strong&gt;: Environment-specific thresholds, allowed regions, service allowlists, and other policy parameters that vary across environments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="policy-esc-screenshot.png" alt="Configuring ESC environments on a policy pack in the Pulumi Cloud console"&gt;&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;You configure ESC environment references on a policy pack within a policy group. At runtime, the values from those environments are resolved and made available to your policies through the policy pack&amp;rsquo;s configuration.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example ESC environment that provides configuration to a compliance policy pack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;compliance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;xxxxxxxxxxxxxxxx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;costThreshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;policyConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cost-compliance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;maxMonthlyCost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${compliance.costThreshold}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;https://compliance.example.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${compliance.apiToken}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;a href="https://www.pulumi.com/docs/esc/environments/syntax/reserved-properties/policy-config/"&gt;&lt;code&gt;policyConfig&lt;/code&gt;&lt;/a&gt; property works just like &lt;a href="https://www.pulumi.com/docs/esc/environments/syntax/reserved-properties/pulumi-config/"&gt;&lt;code&gt;pulumiConfig&lt;/code&gt;&lt;/a&gt; does for stacks. Values nested under each policy name are made available as configuration to that policy at runtime. Secrets remain encrypted and are only decrypted when the environment is resolved.&lt;/p&gt;
&lt;p&gt;You can also use the &lt;code&gt;environmentVariables&lt;/code&gt; property to inject values as environment variables into the policy runtime, following the same pattern as &lt;a href="https://www.pulumi.com/docs/esc/environments/syntax/reserved-properties/environment-variables/"&gt;stack environment variables&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="example-compliance-api-validation"&gt;Example: compliance API validation&lt;/h2&gt;
&lt;p&gt;Consider a policy that validates every new resource against an external compliance API before it can be provisioned. The API requires an authentication token and returns whether the resource configuration meets your organization&amp;rsquo;s compliance standards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt;, the API token lived in the policy group configuration in plain text. Rotating the token meant updating every policy group. There was no audit trail for who accessed the credential, and no way to use different API endpoints for staging and production compliance checks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;After&lt;/strong&gt;, the API token lives in an ESC environment. You get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Centralized rotation&lt;/strong&gt;: Update the token in one place and every policy group that references the environment picks up the change&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Access controls&lt;/strong&gt;: ESC&amp;rsquo;s role-based access controls govern who can view or modify the credential&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit trail&lt;/strong&gt;: Every access to the environment is logged&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environment separation&lt;/strong&gt;: Use different ESC environments for different policy groups, so staging policies validate against a staging compliance endpoint while production policies use the production endpoint&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;To start using ESC environments with your policy packs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/environments/working-with-environments/"&gt;Create an ESC environment&lt;/a&gt; with your policy configuration and secrets&lt;/li&gt;
&lt;li&gt;Attach the environment to a policy pack in your policy group through the Pulumi Cloud console&lt;/li&gt;
&lt;li&gt;Update your policies to read from the configuration values provided by the environment&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To learn more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/environments/syntax/reserved-properties/policy-config/"&gt;&lt;code&gt;policyConfig&lt;/code&gt; reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/insights/policy/policy-packs/"&gt;Policy packs documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/get-started/"&gt;Get started with Pulumi ESC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Dan Biwer</author><category>esc</category><category>policy-as-code</category><category>features</category></item><item><title>Pulumi Cloud REST API Docs, Now Generated from OpenAPI</title><link>https://www.pulumi.com/blog/rest-api-docs-from-openapi/</link><pubDate>Mon, 20 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/rest-api-docs-from-openapi/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/rest-api-docs-from-openapi/index.png" /&gt;
&lt;p&gt;The &lt;a href="https://www.pulumi.com/docs/reference/cloud-rest-api/"&gt;Pulumi Cloud REST API reference&lt;/a&gt; is now generated directly from the live &lt;a href="https://api.pulumi.com/api/openapi/pulumi-spec.json"&gt;OpenAPI spec&lt;/a&gt; at build time. Every endpoint, parameter, request body, and response schema you see on the page comes from the same spec the API itself publishes. The docs now stay in sync with the API automatically!&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;The previous REST API reference was a set of handwritten pages. That meant every new endpoint, renamed parameter, or revised response shape needed a matching docs PR, and in practice the pages drifted. Small inconsistencies added up: missing parameters, outdated request shapes, schemas that no longer matched what the API returned. We wanted a durable fix that keeps the docs in sync as the API grows.&lt;/p&gt;
&lt;p&gt;Generating the reference from the OpenAPI spec closes that gap. When the API ships a change, the docs pick it up automatically the next time our docs are built.&lt;/p&gt;
&lt;h2 id="whats-new"&gt;What&amp;rsquo;s new&lt;/h2&gt;
&lt;p&gt;The reference at &lt;code&gt;/docs/reference/cloud-rest-api/&lt;/code&gt; now includes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find what you need faster
&lt;ul&gt;
&lt;li&gt;Endpoints are grouped by product area — Stacks, Deployments, Environments, Organizations, Registry, Insights, AI, Workflows, and more — so you can jump straight to the part of the API you&amp;rsquo;re working with.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Complete request and response details
&lt;ul&gt;
&lt;li&gt;Every endpoint documents its parameters, request body, and the exact shape of what it returns, so you know what to send and what to expect back without guessing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;One-click navigation between related types
&lt;ul&gt;
&lt;li&gt;When a response references another object, the type name is a link. Click through to drill into its full definition if desired instead of scrolling a lengthy API reference page.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="what-this-unlocks-for-agents"&gt;What this unlocks for agents&lt;/h2&gt;
&lt;p&gt;Keeping the reference in sync with the spec isn&amp;rsquo;t just a human convenience. It changes what&amp;rsquo;s reliable for AI agents that read the docs and call the API on your behalf. An agent reading a handwritten reference might see a parameter that was renamed six months ago, or miss a field the API now returns, and the call fails silently or in ways that are hard to debug. When the reference is generated from the spec, the agent is working from what the API actually accepts today.&lt;/p&gt;
&lt;p&gt;Say you&amp;rsquo;re onboarding a new team and need to stand up their access in Pulumi Cloud. Point an agent at the REST API reference and ask it to create an &lt;code&gt;sre-oncall&lt;/code&gt; team, add four members, and grant admin on three stacks. The agent walks the teams, memberships, and stack-permissions endpoints, builds the right sequence of calls, and executes.&lt;/p&gt;
&lt;p&gt;The same pattern holds for bulk audits and cleanup. Ask an agent to find every stack in your org with no recent updates and tag them &lt;code&gt;stale&lt;/code&gt;, and it can paginate correctly because the response schema matches reality. While workflows like these were technically possible before, they&amp;rsquo;re much more reliable now.&lt;/p&gt;
&lt;h2 id="same-url-existing-links-keep-working"&gt;Same URL, existing links keep working&lt;/h2&gt;
&lt;p&gt;The generated docs live at the same URL as the previous reference: &lt;code&gt;/docs/reference/cloud-rest-api/&lt;/code&gt;. Bookmarks, blog links, and inbound search traffic still land on the right page. Redirects are in place for any API reference docs page that has been tweaked, renamed, or moved.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Start at the new &lt;a href="https://www.pulumi.com/docs/reference/cloud-rest-api/"&gt;REST API reference&lt;/a&gt; and browse by category. Each page links through to the request and response object schemas it uses.&lt;/p&gt;
&lt;p&gt;If you spot anything that looks wrong, the most likely culprit is the OpenAPI spec itself — file an issue in &lt;a href="https://github.com/pulumi/docs"&gt;pulumi/docs&lt;/a&gt; and we&amp;rsquo;ll trace it back to the source. For tag intros and structural improvements, PRs to &lt;a href="https://github.com/pulumi/docs"&gt;pulumi/docs&lt;/a&gt; are welcome. Questions and feedback are always welcome in the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/docs/reference/cloud-rest-api/"
class="btn btn-primary"
&gt;
Explore the REST API
&lt;/a&gt;</description><author>Devon Grove</author><category>pulumi-cloud</category><category>features</category><category>api</category></item><item><title>Bitbucket Cloud Meets Pulumi Cloud</title><link>https://www.pulumi.com/blog/bitbucket-vcs-integration/</link><pubDate>Mon, 20 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/bitbucket-vcs-integration/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/bitbucket-vcs-integration/index.png" /&gt;
&lt;p&gt;Pulumi Cloud now supports Bitbucket Cloud as a first-class VCS integration, joining &lt;a href="https://www.pulumi.com/docs/version-control/github-app/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/version-control/gitlab/"&gt;GitLab&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/version-control/azure-devops-integration/"&gt;Azure DevOps&lt;/a&gt;. Connect your Bitbucket workspace to deploy infrastructure on every push, preview changes on pull requests, spin up ephemeral review stacks, and get AI-powered change summaries — all without an external CI/CD pipeline.&lt;/p&gt;
&lt;h2 id="deploy-infrastructure-from-bitbucket"&gt;Deploy infrastructure from Bitbucket&lt;/h2&gt;
&lt;p&gt;Connect a Bitbucket repository to a stack and infrastructure deploys automatically when you push to your configured branch. Configure path filters so only relevant file changes trigger deployments, and manage environment variables and secrets directly in Pulumi Cloud. No external CI/CD pipeline required.&lt;/p&gt;
&lt;p&gt;Every pull request gets an infrastructure preview showing exactly what will change before merging. &lt;a href="https://www.pulumi.com/product/neo/"&gt;Neo&lt;/a&gt; posts AI-generated summaries explaining what the changes mean in plain language, so reviewers can understand the impact without reading resource diffs.&lt;/p&gt;
&lt;h2 id="two-ways-to-connect"&gt;Two ways to connect&lt;/h2&gt;
&lt;p&gt;The integration supports two authentication methods depending on your Bitbucket plan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Personal OAuth&lt;/strong&gt; works with every workspace, including free plans. Authorize through the standard OAuth flow and you&amp;rsquo;re connected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Workspace tokens&lt;/strong&gt; are available for Premium workspaces. Generate a token with the required scopes (&lt;code&gt;repository:admin&lt;/code&gt;, &lt;code&gt;repository:write&lt;/code&gt;, &lt;code&gt;pullrequest:write&lt;/code&gt;, &lt;code&gt;webhook&lt;/code&gt;) and paste it into Pulumi Cloud for a service-account-style connection that isn&amp;rsquo;t tied to an individual user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both methods register webhooks automatically — no manual configuration required.&lt;/p&gt;
&lt;h2 id="scaffold-new-projects-from-your-repositories"&gt;Scaffold new projects from your repositories&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://www.pulumi.com/docs/idp/concepts/new-project-wizard/"&gt;new project wizard&lt;/a&gt; discovers your Bitbucket workspace, repositories, and branches so you can scaffold and deploy a new stack without leaving Pulumi Cloud. Create a new repository directly from the wizard or select an existing one and configure VCS-backed deployments in a few clicks.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;An org admin configures the integration under &lt;strong&gt;Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Version control&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Authorize with Bitbucket using personal OAuth or a workspace token.&lt;/li&gt;
&lt;li&gt;Deploy infrastructure with first-class workflows.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For full setup details, see the &lt;a href="https://www.pulumi.com/docs/version-control/bitbucket/"&gt;Bitbucket integration docs&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://app.pulumi.com/signin"
class="btn btn-primary"
target="_blank"
rel="noopener noreferrer"
&gt;
Connect your Bitbucket workspace
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular text-sm ml-2" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-arrow-square-out-regular"/&gt;&lt;/svg&gt;
&lt;/a&gt;</description><author>Luke Ward</author><category>bitbucket</category><category>features</category><category>pulumi-cloud</category></item><item><title>Scan AWS GovCloud and more partitions with Pulumi Insights</title><link>https://www.pulumi.com/blog/scan-aws-govcloud-china-with-pulumi-insights/</link><pubDate>Tue, 14 Apr 2026 09:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/scan-aws-govcloud-china-with-pulumi-insights/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/scan-aws-govcloud-china-with-pulumi-insights/index.png" /&gt;
&lt;p&gt;Pulumi Insights account scanning now supports every AWS partition. If your workloads run in GovCloud, China, the European Sovereign Cloud, or one of the ISO intelligence-community clouds, you can get the same resource discovery, cross-account search, and AI-assisted insights that commercial accounts already have.&lt;/p&gt;
&lt;h2 id="supported-partitions"&gt;Supported partitions&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;AWS Standard (Commercial)&lt;/li&gt;
&lt;li&gt;AWS GovCloud (US)&lt;/li&gt;
&lt;li&gt;AWS ISO (US)&lt;/li&gt;
&lt;li&gt;AWS ISOB (US)&lt;/li&gt;
&lt;li&gt;AWS ISOF (US)&lt;/li&gt;
&lt;li&gt;AWS ISOE (Europe)&lt;/li&gt;
&lt;li&gt;AWS European Sovereign Cloud&lt;/li&gt;
&lt;li&gt;AWS China&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can also exclude specific regions from discovery — useful when regions are disabled by SCPs or fall outside an audit&amp;rsquo;s scope.&lt;/p&gt;
&lt;p&gt;&lt;img src="aws-partition-picker.png" alt="Choosing an AWS partition when creating an Insights account"&gt;&lt;/p&gt;
&lt;h2 id="set-it-up"&gt;Set it up&lt;/h2&gt;
&lt;p&gt;In the Pulumi Cloud console:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Accounts → Create account&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;AWS&lt;/strong&gt; as the provider.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Add your configuration&lt;/strong&gt;, pick the target partition.&lt;/li&gt;
&lt;li&gt;Supply credentials via a Pulumi ESC environment. The OIDC trust policy uses the partition-appropriate ARN prefix (&lt;code&gt;arn:aws-us-gov:&lt;/code&gt;, &lt;code&gt;arn:aws-cn:&lt;/code&gt;, etc.).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For IAM and ESC setup, see the &lt;a href="https://www.pulumi.com/docs/insights/discovery/accounts/"&gt;Insights accounts docs&lt;/a&gt;. Log in to &lt;a href="https://app.pulumi.com/"&gt;Pulumi Cloud&lt;/a&gt; to get started.&lt;/p&gt;</description><author>Alejandro Cotroneo</author><category>insights</category><category>aws</category><category>features</category><category>cloud-engineering</category></item><item><title>Introducing Bun as a Runtime for Pulumi</title><link>https://www.pulumi.com/blog/introducing-bun-as-a-runtime-for-pulumi/</link><pubDate>Wed, 08 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/introducing-bun-as-a-runtime-for-pulumi/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/introducing-bun-as-a-runtime-for-pulumi/index.png" /&gt;
&lt;p&gt;Last year we added support for &lt;a href="https://www.pulumi.com/blog/bun-package-manager/"&gt;Bun as a package manager&lt;/a&gt; for Pulumi TypeScript projects. Today we&amp;rsquo;re taking the next step: Bun is now a fully supported runtime for Pulumi programs. Set &lt;code&gt;runtime: bun&lt;/code&gt; in your &lt;code&gt;Pulumi.yaml&lt;/code&gt; and Bun will execute your entire Pulumi program, with no Node.js required. Since Bun&amp;rsquo;s 1.0 release, this has been one of our &lt;a href="https://github.com/pulumi/pulumi/issues/13904"&gt;most requested features&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="why-bun"&gt;Why Bun?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://bun.sh/"&gt;Bun&lt;/a&gt; is a JavaScript runtime designed as an all-in-one toolkit: runtime, package manager, bundler, and test runner. For Pulumi users, the most relevant advantages are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Native TypeScript support&lt;/strong&gt;: Bun runs TypeScript directly without requiring &lt;a href="https://typestrong.org/ts-node/"&gt;ts-node&lt;/a&gt; or a separate compile step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fast package management&lt;/strong&gt;: Bun&amp;rsquo;s built-in package manager can install dependencies significantly faster than npm.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node.js compatibility&lt;/strong&gt;: Bun &lt;a href="https://bun.sh/docs/runtime/nodejs-apis"&gt;aims for 100% Node.js compatibility&lt;/a&gt;, so the npm packages you already use with Pulumi should work out of the box.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With &lt;code&gt;runtime: bun&lt;/code&gt;, Pulumi uses Bun for both running your program and managing your packages, giving you a streamlined single-tool experience.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;To create a new Pulumi project with the Bun runtime, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi new bun
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This creates a TypeScript project configured to use Bun. The generated &lt;code&gt;Pulumi.yaml&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-bun-project&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;bun&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From here, write your Pulumi program as usual. For example, to create a random password using the &lt;code&gt;@pulumi/random&lt;/code&gt; package:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bun add @pulumi/random
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;random&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/random&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RandomPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;length&lt;/span&gt;: &lt;span class="kt"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then deploy with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bun.sh/docs/installation"&gt;Bun&lt;/a&gt; 1.3 or later&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/iac/download-install/"&gt;Pulumi&lt;/a&gt; 3.227.0 or later&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="converting-existing-nodejs-projects"&gt;Converting existing Node.js projects&lt;/h2&gt;
&lt;p&gt;If you have an existing Pulumi TypeScript project running on Node.js, you can convert it to use the Bun runtime in a few steps.&lt;/p&gt;
&lt;h3 id="1-update-pulumiyaml"&gt;1. Update &lt;code&gt;Pulumi.yaml&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Change the &lt;code&gt;runtime&lt;/code&gt; field from &lt;code&gt;nodejs&lt;/code&gt; to &lt;code&gt;bun&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;nodejs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;packagemanager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;npm&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;bun&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;When the runtime is set to &lt;code&gt;bun&lt;/code&gt;, Bun is also used as the package manager — there&amp;rsquo;s no need to configure a separate &lt;code&gt;packagemanager&lt;/code&gt; option.&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="2-update-tsconfigjson"&gt;2. Update &lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Bun handles TypeScript differently from Node.js with &lt;code&gt;ts-node&lt;/code&gt;. Update your &lt;code&gt;tsconfig.json&lt;/code&gt; to use &lt;a href="https://bun.sh/docs/typescript#suggested-compileroptions"&gt;Bun&amp;rsquo;s recommended compiler options&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;compilerOptions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;lib&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ESNext&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;target&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ESNext&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;module&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Preserve&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;moduleDetection&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;force&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;moduleResolution&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;bundler&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;allowJs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;allowImportingTsExtensions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;verbatimModuleSyntax&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;strict&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;skipLibCheck&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;noFallthroughCasesInSwitch&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;noUncheckedIndexedAccess&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;noImplicitOverride&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Key differences from a typical Node.js &lt;code&gt;tsconfig.json&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.typescriptlang.org/tsconfig/#module"&gt;&lt;code&gt;module: &amp;quot;Preserve&amp;quot;&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#moduleresolution-bundler"&gt;&lt;code&gt;moduleResolution: &amp;quot;bundler&amp;quot;&lt;/code&gt;&lt;/a&gt;: Let Bun handle module resolution instead of compiling to CommonJS. The &lt;code&gt;bundler&lt;/code&gt; resolution strategy allows extensionless imports while still respecting &lt;code&gt;package.json&lt;/code&gt; exports, matching how Bun resolves modules in practice.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax"&gt;&lt;code&gt;verbatimModuleSyntax: true&lt;/code&gt;&lt;/a&gt;: Enforces consistent use of ESM &lt;code&gt;import&lt;/code&gt;/&lt;code&gt;export&lt;/code&gt; syntax. TypeScript will flag any remaining CommonJS patterns like &lt;code&gt;require()&lt;/code&gt; at compile time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-switch-to-esm"&gt;3. Switch to ESM&lt;/h3&gt;
&lt;p&gt;Bun makes it easy to go full ESM and it&amp;rsquo;s the &lt;a href="https://bun.sh/docs/runtime/module-resolution"&gt;recommended module format&lt;/a&gt; for Bun projects. Add &lt;code&gt;&amp;quot;type&amp;quot;: &amp;quot;module&amp;quot;&lt;/code&gt; to your &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;module&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules"&gt;ECMAScript module (ESM)&lt;/a&gt; syntax, one thing that gets easier is working with async code. In a CommonJS Pulumi program, if you need to await a data source or other async call before declaring resources, the program must be wrapped in an &lt;a href="https://www.pulumi.com/docs/iac/languages-sdks/javascript/#enabling-async-support"&gt;async entrypoint function&lt;/a&gt;. With ESM and Bun, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top_level_await"&gt;top-level await&lt;/a&gt; just works, so you can skip the wrapper function entirely and &lt;code&gt;await&lt;/code&gt; directly at the module level:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;azs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAvailabilityZones&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;available&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buckets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;az&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BucketV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`my-bucket-&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;az&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucketNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If your existing program does use an async entrypoint with &lt;code&gt;export =&lt;/code&gt;, just replace it with the ESM-standard &lt;code&gt;export default&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// CommonJS (Node.js default)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BucketV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;my-bucket&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;: &lt;span class="kt"&gt;bucket.id&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ESM (used with Bun)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BucketV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;my-bucket&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;: &lt;span class="kt"&gt;bucket.id&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-update-the-pulumi-sdk"&gt;4. Update the Pulumi SDK&lt;/h3&gt;
&lt;p&gt;Make sure you&amp;rsquo;re running &lt;code&gt;@pulumi/pulumi&lt;/code&gt; version 3.226.0 or later:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bun add @pulumi/pulumi@latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="5-install-dependencies-and-deploy"&gt;5. Install dependencies and deploy&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi install
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="bun-as-runtime-vs-bun-as-package-manager"&gt;Bun as runtime vs. Bun as package manager&lt;/h2&gt;
&lt;p&gt;With this release, there are now two ways to use Bun with Pulumi:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Bun&amp;rsquo;s role&lt;/th&gt;
&lt;th&gt;Node.js required?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;runtime: bun&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runs your program and manages packages&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;runtime: { name: nodejs, options: { packagemanager: bun } }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Manages packages only&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use &lt;code&gt;runtime: bun&lt;/code&gt; for the full Bun experience. The package-manager-only mode is still available for projects that need Node.js-specific features like function serialization.&lt;/p&gt;
&lt;h2 id="known-limitations"&gt;Known limitations&lt;/h2&gt;
&lt;p&gt;The following Pulumi features are not currently supported when using the Bun runtime:&lt;/p&gt;
&lt;div class="note note-warning"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-warning-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/docs/iac/clouds/aws/guides/lambda/"&gt;Callback functions (magic lambdas)&lt;/a&gt;&lt;/strong&gt; are not supported. APIs like &lt;code&gt;aws.lambda.CallbackFunction&lt;/code&gt; and event handler shortcuts (e.g., &lt;code&gt;bucket.onObjectCreated&lt;/code&gt;) use &lt;a href="https://www.pulumi.com/docs/iac/concepts/functions/function-serialization/"&gt;function serialization&lt;/a&gt; which requires Node.js &lt;code&gt;v8&lt;/code&gt; and &lt;code&gt;inspector&lt;/code&gt; modules that are only partially supported in Bun.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/docs/iac/concepts/providers/dynamic-providers/"&gt;Dynamic providers&lt;/a&gt;&lt;/strong&gt; are not supported. Dynamic providers (&lt;code&gt;pulumi.dynamic.Resource&lt;/code&gt;) similarly rely on &lt;a href="https://www.pulumi.com/docs/iac/concepts/functions/function-serialization/"&gt;function serialization&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If your project uses any of these features, continue using &lt;code&gt;runtime: nodejs&lt;/code&gt;. You can still benefit from Bun&amp;rsquo;s fast package management by setting &lt;code&gt;packagemanager: bun&lt;/code&gt; in your runtime options.&lt;/p&gt;
&lt;h2 id="start-using-bun-with-pulumi"&gt;Start using Bun with Pulumi&lt;/h2&gt;
&lt;p&gt;Bun runtime support is available now in &lt;a href="https://www.pulumi.com/docs/iac/download-install/"&gt;Pulumi 3.227.0&lt;/a&gt;. To get started:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a new project: &lt;code&gt;pulumi new bun&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Read the docs: &lt;a href="https://www.pulumi.com/docs/iac/languages-sdks/javascript/"&gt;TypeScript (Node.js) SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Report issues or share feedback on &lt;a href="https://github.com/pulumi/pulumi/issues"&gt;GitHub&lt;/a&gt; or in the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you to everyone who upvoted, commented on, and contributed to &lt;a href="https://github.com/pulumi/pulumi/issues/13904"&gt;the original feature request&lt;/a&gt;. Your feedback helped shape this feature, and we&amp;rsquo;d love to hear how it works for you.&lt;/p&gt;</description><author>Julien Poissonnier</author><category>features</category><category>typescript</category><category>bun</category></item><item><title>Introducing the pulumi policy analyze Command for Existing Stacks</title><link>https://www.pulumi.com/blog/pulumi-policy-analyze-existing-stacks/</link><pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-policy-analyze-existing-stacks/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-policy-analyze-existing-stacks/index.png" /&gt;
&lt;p&gt;You can now run &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-packs/"&gt;policy packs&lt;/a&gt; against your existing stack state without running your Pulumi program or making provider calls. The new &lt;code&gt;pulumi policy analyze&lt;/code&gt; command evaluates your current infrastructure against local policy packs directly, turning policy validation into a fast, repeatable check.&lt;/p&gt;
&lt;h2 id="why-this-command-matters"&gt;Why this command matters&lt;/h2&gt;
&lt;p&gt;Policy authoring and policy updates usually involve an iteration loop:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make a policy change.&lt;/li&gt;
&lt;li&gt;Run a policy check.&lt;/li&gt;
&lt;li&gt;Inspect violations or remediations.&lt;/li&gt;
&lt;li&gt;Repeat until the policy behavior matches intent.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Before this command, that loop often depended on &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_preview/"&gt;&lt;code&gt;pulumi preview&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_up/"&gt;&lt;code&gt;pulumi up&lt;/code&gt;&lt;/a&gt;, which can be heavier than you need when your goal is validating policy logic against known state.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;pulumi policy analyze&lt;/code&gt;, you can evaluate your current stack state directly and quickly.&lt;/p&gt;
&lt;h2 id="basic-usage"&gt;Basic usage&lt;/h2&gt;
&lt;p&gt;At minimum, provide a policy pack path and optionally a stack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi policy analyze &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --policy-pack ./policy-pack &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --stack dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also pass a config file for each policy pack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi policy analyze &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --policy-pack ./policy-pack &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --policy-pack-config ./policy-config.dev.json &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --stack dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If any mandatory policy violations are found, the command exits non-zero.&lt;/p&gt;
&lt;p&gt;If remediation policies fire, those changes are reported in output, but stack state is not modified.&lt;/p&gt;
&lt;h2 id="testing-new-policy-packs-as-a-developer"&gt;Testing new policy packs as a developer&lt;/h2&gt;
&lt;p&gt;For policy pack development, this command is useful as a tight local feedback loop:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pick a representative stack (&lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt;, or a fixture stack).&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pulumi policy analyze&lt;/code&gt; against that stack after each policy change.&lt;/li&gt;
&lt;li&gt;Use the output to verify mandatory, advisory, and remediation behavior.&lt;/li&gt;
&lt;li&gt;Repeat before publishing the policy pack or attaching it to broader policy groups.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Two output modes are especially useful:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;--diff&lt;/code&gt; for a concise, human-readable view while iterating locally.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--json&lt;/code&gt; for structured output that can be consumed in scripts and CI.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="using-it-in-ai-and-agent-workflows"&gt;Using it in AI and agent workflows&lt;/h2&gt;
&lt;p&gt;This command is also a good primitive for AI-assisted policy workflows.&lt;/p&gt;
&lt;p&gt;Because &lt;code&gt;pulumi policy analyze&lt;/code&gt; can emit JSON and a clear process exit code, agents can use it for deterministic policy evaluation steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Propose or edit policy rules.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pulumi policy analyze --json&lt;/code&gt; against target stacks.&lt;/li&gt;
&lt;li&gt;Parse violations and remediation signals.&lt;/li&gt;
&lt;li&gt;Suggest policy fixes, config adjustments, or targeted infrastructure changes.&lt;/li&gt;
&lt;li&gt;Re-run analysis until mandatory violations are resolved.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example, an agent tasked with fixing a policy violation can run &lt;code&gt;pulumi policy analyze --json&lt;/code&gt; to get a structured list of violations, identify which resources are non-compliant, generate targeted infrastructure changes, then re-run analysis to confirm the violations are resolved, all without triggering a full preview on each iteration. The same loop works for policy authoring: an agent can propose a new policy rule, test it against several representative stacks, and surface unintended violations before the rule is published.&lt;/p&gt;
&lt;p&gt;This works well for automation because the command doesn&amp;rsquo;t execute your Pulumi program or make provider calls, so there are no side effects or runtime variance between runs. The JSON output and non-zero exit code on failure give agents a clear pass/fail contract to build on.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pulumi policy analyze&lt;/code&gt; is available in &lt;a href="https://github.com/pulumi/pulumi/releases/tag/v3.229.0"&gt;Pulumi v3.229.0&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you are authoring or tuning policy packs, start by running this command against a known stack in your environment. It is a quick way to validate policy behavior before rollout.&lt;/p&gt;
&lt;p&gt;For implementation details, see the merged PR: &lt;a href="https://github.com/pulumi/pulumi/pull/22250"&gt;pulumi/pulumi#22250&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/docs/insights/policy/"
class="btn btn-primary"
&gt;
Get started with policy as code
&lt;/a&gt;</description><author>Fraser Waters</author><category>policy-as-code</category><category>features</category><category>infrastructure-as-code</category><category>ai</category></item><item><title>Neo Plan Mode: Iterate Before You Execute</title><link>https://www.pulumi.com/blog/neo-plan-mode/</link><pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/neo-plan-mode/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-plan-mode/index.png" /&gt;
&lt;p&gt;Infrastructure work ranges from simple updates to complex multi-stack operations. For straightforward tasks, jumping straight to execution is often fine. But complex tasks benefit from deliberate upfront thinking: understanding what exists, identifying dependencies, and agreeing on an approach before anything changes. Today we&amp;rsquo;re launching Plan Mode, a dedicated experience for collaborating with Neo on a detailed plan before execution begins.&lt;/p&gt;
&lt;h2 id="plan-mode"&gt;Plan Mode&lt;/h2&gt;
&lt;p&gt;Without dedicated planning, Neo balances planning with progress toward execution. That works well for many tasks, but complex operations benefit from more thorough upfront discovery. Plan Mode now makes upfront deliberation a first-class workflow, where instead of focusing on getting to execution, Neo focuses entirely on discovery and synthesis until you explicitly approve the plan.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Enter Plan Mode by selecting the plan button when starting a task. Neo shifts its behavior:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Discovery&lt;/strong&gt;: Neo investigates your environment — examining existing infrastructure, reading relevant code, checking dependencies, and researching patterns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Synthesis&lt;/strong&gt;: From that research, Neo produces a plan explaining what it will do and why. The plan references specific things Neo discovered, like a particular stack configuration or dependency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refinement&lt;/strong&gt;: You refine the plan through normal conversation, challenging assumptions, asking for an alternative approach, or requesting more detail on a specific area.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Approval&lt;/strong&gt;: Once you&amp;rsquo;re satisfied, you approve the plan and execution begins. Neo carries forward everything it learned during discovery, so the transition from planning to execution is seamless.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it&lt;/h2&gt;
&lt;p&gt;Plan Mode is opt-in. You choose it when you want to work through an approach before committing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complex multi-stack operations&lt;/strong&gt; where understanding dependencies matters&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unfamiliar infrastructure&lt;/strong&gt; where discovery reduces churn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autonomous execution&lt;/strong&gt; where plan approval is your key control point before Neo runs without step-by-step oversight&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Plan Mode is available now for all Pulumi Cloud organizations. It works with any &lt;a href="https://www.pulumi.com/docs/ai/tasks/#task-modes"&gt;task mode&lt;/a&gt;, so you can pair thorough upfront planning with whatever level of execution autonomy fits the situation.&lt;/p&gt;
&lt;p&gt;To try it, &lt;a href="https://app.pulumi.com/neo"&gt;open Neo in Pulumi Cloud&lt;/a&gt;. For more details, see the &lt;a href="https://www.pulumi.com/docs/ai/tasks/#plan-mode"&gt;Plan Mode documentation&lt;/a&gt;.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>pulumi-neo</category><category>ai</category><category>features</category></item><item><title>Introducing Read-Only Mode for Pulumi Neo</title><link>https://www.pulumi.com/blog/neo-read-only-mode/</link><pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/neo-read-only-mode/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-read-only-mode/index.png" /&gt;
&lt;p&gt;A platform engineer with broad access might want Neo to analyze infrastructure and suggest changes, but include guarantees it won&amp;rsquo;t actually apply them. Read-only mode makes that possible: Neo does the heavy lifting and hands off a pull request for your existing deployment process to pick up.&lt;/p&gt;
&lt;h2 id="control-what-neo-can-change"&gt;Control what Neo can change&lt;/h2&gt;
&lt;p&gt;Neo runs with the permissions of the user who creates a task, but you often want a tighter boundary. Read-only mode solves this by letting you cap Neo&amp;rsquo;s permissions at task creation time. Neo can still read your infrastructure, run previews, and open pull requests, but it cannot deploy, update, or destroy resources.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;When you create a Neo task, you now choose between two permission levels:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left"&gt;Option&lt;/th&gt;
&lt;th style="text-align: left"&gt;What Neo can do&lt;/th&gt;
&lt;th style="text-align: left"&gt;Availability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;Use my permissions&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;Full access (current default behavior)&lt;/td&gt;
&lt;td style="text-align: left"&gt;All tiers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;Read-only&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;Read, preview, and create PRs. No infrastructure mutations.&lt;/td&gt;
&lt;td style="text-align: left"&gt;All tiers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Read-only mode takes your existing permissions and removes the ability to make changes. Neo remains fully active, meaning it can still read your infrastructure state, run previews, write and refactor code, create branches, and open pull requests. If Neo encounters an operation it can&amp;rsquo;t perform in read-only mode, the operation fails and Neo reports what it would have done. The only difference is that Neo cannot trigger deployments or other write operations in Pulumi Cloud directly.&lt;/p&gt;
&lt;h2 id="read-only-mode-and-auto-approve"&gt;Read-only mode and auto-approve&lt;/h2&gt;
&lt;p&gt;Neo&amp;rsquo;s &lt;a href="https://www.pulumi.com/docs/ai/tasks/#task-modes"&gt;operating modes&lt;/a&gt; let you choose how much oversight you want: review mode for full approval at each step, balanced mode for approving only mutating operations, and auto mode for hands-off execution.&lt;/p&gt;
&lt;p&gt;Read-only mode pairs well with auto-approve. Because Neo cannot perform write operations like deployments or destroys, you can let it run autonomously and trust that the output is a pull request, not a production change. Kick off a task, let Neo work in the background, and come back to a ready-to-review PR.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;Read-only mode is available today for all Pulumi Cloud users.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://app.pulumi.com/signin"&gt;Sign in to Pulumi Cloud&lt;/a&gt; and select &lt;strong&gt;Read-only&lt;/strong&gt; when creating your next Neo task&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/ai/"&gt;Read the Neo documentation&lt;/a&gt; for detailed guides on permission levels&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slack.pulumi.com/"&gt;Join the Community Slack&lt;/a&gt; to share your feedback&lt;/li&gt;
&lt;/ul&gt;</description><author>Florian Stadler</author><category>pulumi-neo</category><category>ai</category><category>features</category></item><item><title>Introducing OTel Tracing in the Pulumi CLI</title><link>https://www.pulumi.com/blog/introducing-otel-tracing-in-the-pulumi-cli/</link><pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/introducing-otel-tracing-in-the-pulumi-cli/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/introducing-otel-tracing-in-the-pulumi-cli/index.png" /&gt;
&lt;p&gt;Tracing is an important part of our CLI observability story. So far we&amp;rsquo;ve relied on (the now deprecated) &lt;a href="https://opentracing.io/"&gt;OpenTracing&lt;/a&gt; for this. We have now added OTel tracing to the CLI, which is more future-proof, and should in most cases give you a better view over what the CLI is doing.&lt;/p&gt;
&lt;h2 id="background"&gt;Background&lt;/h2&gt;
&lt;p&gt;We introduced tracing using &lt;a href="https://opentracing.io"&gt;OpenTracing&lt;/a&gt; &lt;a href="https://github.com/pulumi/pulumi/pull/521"&gt;all the way back in 2017&lt;/a&gt;, before &lt;a href="https://opentelemetry.io/"&gt;OpenTelemetry&lt;/a&gt; was a thing. This served us well over the years, but as OpenTracing was deprecated, and OTel emerged as the new and maintained thing, it got harder and harder to justify further investment in a tracing infrastructure that was deprecated. Last year we started focusing more on performance, and it became more and more clear that we&amp;rsquo;d either have to enhance our current OpenTracing setup, or do the work to switch to OTel.&lt;/p&gt;
&lt;p&gt;In the end it was a relatively easy decision to move to the more modern and fully supported OTel, especially as more and more tooling around it starts emerging.&lt;/p&gt;
&lt;h2 id="enter-otel"&gt;Enter OTel&lt;/h2&gt;
&lt;p&gt;With the decision to move to OTel made, the only thing left to decide was how to implement it. There were a couple of constraints we faced here. First, we wanted to make sure that traces are easily shareable. This means ideally a text file in whatever format, that can be shared easily. Second, pulumi&amp;rsquo;s plugin system works by spawning a new process per plugin. We want to get traces from each of these plugins to make sure we have as much coverage as possible. And third, ideally we also want to get traces from plugins that only implement OpenTracing, but not OTel yet, since someone can upgrade the CLI, but not the plugins for example.&lt;/p&gt;
&lt;p&gt;Given these constraints, we decided to implement an OTel collector in the CLI, that could then forward the traces to whatever output format we want. This means that plugins only ever need to send traces back to the CLI over &lt;a href="https://grpc.io/"&gt;gRPC&lt;/a&gt;, and the CLI will do any further processing. This means only one process will write to the file, if requested.&lt;/p&gt;
&lt;p&gt;For plugins we always request both OpenTracing and OTel traces. If both are requested and OTel is supported by the plugin, the plugin is expected to only send the OTel version of the traces. For OpenTracing traces, we collect them in the collector in the CLI, and then translate them internally to OTel traces. This way we can still get the traces from older plugins, without them needing to change anything.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Currently the OTel exporter supports both exporting the traces directly via gRPC to a collector, or to a file, where the traces are JSON encoded. This file can then be shared and imported into a trace viewer at a later time. To do this, you can use the &lt;code&gt;--otel-traces &amp;lt;file://&amp;lt;filename&amp;gt;|grpc://&amp;lt;exporter-address&amp;gt;&amp;gt;&lt;/code&gt; flag, using pulumi version v3.226 or newer. For further documentation see &lt;a href="https://www.pulumi.com/docs/support/debugging/performance-tracing/#opentelemetry-tracing"&gt;our performance tracing docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To view the traces, you can use one of the various exporters that exist. Popular options include &lt;a href="https://www.jaegertracing.io/"&gt;Jaeger&lt;/a&gt;, &lt;a href="https://github.com/CtrlSpice/otel-desktop-viewer"&gt;OTel Desktop Viewer&lt;/a&gt;, or &lt;a href="https://github.com/ymtdzzz/otel-tui"&gt;OTel TUI&lt;/a&gt; if you prefer not leaving your terminal. Once you&amp;rsquo;ve ingested the logs there either by uploading the trace file, or sending them directly by giving pulumi the exporter address, look for the &lt;code&gt;pulumi-cli: pulumi&lt;/code&gt; root span.&lt;/p&gt;
&lt;p&gt;All further spans will be parented to that root span, and you should thus be able to see a nice flow diagram in the viewer of your choice.&lt;/p&gt;
&lt;p&gt;As always, we would love any feedback either in the &lt;a href="https://slack.pulumi.com/"&gt;Community Slack&lt;/a&gt;, or through a &lt;a href="https://github.com/pulumi/pulumi/issues"&gt;GitHub issue&lt;/a&gt;.&lt;/p&gt;</description><author>Thomas Gummerer</author><category>features</category><category>pulumi-cli</category></item><item><title>Pulumi IAM Expands: Manage Access at Scale with Tags, Roles, and Teams</title><link>https://www.pulumi.com/blog/expanding-pulumi-iam-custom-permissions/</link><pubDate>Thu, 19 Mar 2026 10:30:00 -0700</pubDate><guid>https://www.pulumi.com/blog/expanding-pulumi-iam-custom-permissions/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/expanding-pulumi-iam-custom-permissions/index.png" /&gt;
&lt;p&gt;Since the launch of &lt;a href="https://www.pulumi.com/blog/pulumi-cloud-iam-launch/"&gt;Pulumi IAM&lt;/a&gt; with &lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/roles/"&gt;custom roles&lt;/a&gt; and scoped &lt;a href="https://www.pulumi.com/docs/administration/access-identity/access-tokens/"&gt;access tokens&lt;/a&gt;, organizations have been using fine-grained permissions to secure their automation and CI/CD pipelines. As teams scale to hundreds or thousands of stacks, environments, and accounts, the next challenge is applying those permissions efficiently.&lt;/p&gt;
&lt;p&gt;Today, we&amp;rsquo;re introducing three new capabilities to help you manage permissions more dynamically at scale: &lt;strong&gt;tag-based access control&lt;/strong&gt;, &lt;strong&gt;team role assignments&lt;/strong&gt;, and &lt;strong&gt;user role assignments&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="why-tag-based-access-control"&gt;Why tag-based access control?&lt;/h2&gt;
&lt;p&gt;With custom roles, you can define granular permissions using &lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/scopes"&gt;fine-grained scopes&lt;/a&gt;. However, applying those roles still requires selecting individual stacks, environments, or accounts one by one. For organizations managing a large number of Pulumi entities, this means either granting overly broad access or spending significant time on manual configuration. Tag-based access control solves this problem.&lt;/p&gt;
&lt;h2 id="whats-new"&gt;What&amp;rsquo;s new?&lt;/h2&gt;
&lt;h3 id="tag-based-access-control"&gt;Tag-based access control&lt;/h3&gt;
&lt;p&gt;You can now create rules within a custom role that dynamically grant permissions based on entity tags. This works across IaC stacks, ESC environments, and Insights accounts. For example, when a new stack is created and tagged &lt;code&gt;env:prod&lt;/code&gt;, anyone with a role containing a matching tag-based rule automatically gets the right permissions. No manual assignment required.&lt;/p&gt;
&lt;p&gt;A single role can include multiple tag-based rules, and they are evaluated with &lt;strong&gt;OR&lt;/strong&gt; logic. If an entity matches any of the rules, the permissions are granted. Within a single rule, you can combine multiple key-value conditions with implicit &lt;strong&gt;AND&lt;/strong&gt; logic for precise targeting. For example, a rule with conditions &lt;code&gt;env:prod&lt;/code&gt; and &lt;code&gt;team:payments&lt;/code&gt; ensures access is granted only to production resources owned by the payments team.&lt;/p&gt;
&lt;h3 id="team-role-assignments"&gt;Team role assignments&lt;/h3&gt;
&lt;p&gt;Custom roles can now be assigned directly to &lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/teams"&gt;teams&lt;/a&gt; within your Pulumi organization. When an engineer joins a team, whether manually or via &lt;a href="https://www.pulumi.com/docs/pulumi-cloud/access-management/scim/"&gt;SCIM provisioning&lt;/a&gt;, they automatically inherit the permissions defined in the team&amp;rsquo;s assigned roles.&lt;/p&gt;
&lt;p&gt;Teams support both &lt;strong&gt;inline permissions&lt;/strong&gt; (ad-hoc access to specific stacks, environments, or accounts) and &lt;strong&gt;role-based permissions&lt;/strong&gt; simultaneously. You can assign &lt;strong&gt;multiple roles&lt;/strong&gt; to a single team, giving you full flexibility to compose access from reusable building blocks while retaining the ability to grant one-off access where needed. If you have existing workflows built around ad-hoc assignments to teams, those continue to work exactly as before. You can adopt roles incrementally or mix both approaches on the same team.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Team admins (or users with the &lt;code&gt;team:update&lt;/code&gt; scope) can continue to manage their team&amp;rsquo;s inline permissions as they do today. However, assigning organization-level custom roles to a team requires additional permissions: &lt;code&gt;role:read&lt;/code&gt; and &lt;code&gt;role:update&lt;/code&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="user-role-assignments"&gt;User role assignments&lt;/h3&gt;
&lt;p&gt;Custom roles can also be assigned directly to individual organization members. This is useful for users whose responsibilities span multiple teams or require permissions beyond the existing org-level &lt;code&gt;Admin&lt;/code&gt;, &lt;code&gt;Member&lt;/code&gt;, and &lt;code&gt;Billing Manager&lt;/code&gt; &lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/roles"&gt;roles&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="how-permissions-work-together"&gt;How permissions work together&lt;/h3&gt;
&lt;p&gt;Permissions in Pulumi IAM are &lt;strong&gt;additive&lt;/strong&gt;. A user receives the union of all permissions granted to them, including permissions from roles assigned directly to them as a user and permissions from roles assigned to any team they belong to. A user on both the &amp;ldquo;SRE&amp;rdquo; and &amp;ldquo;Security&amp;rdquo; teams inherits permissions from both team roles, plus any role assigned to them individually.&lt;/p&gt;
&lt;h2 id="how-to-get-started"&gt;How to get started&lt;/h2&gt;
&lt;p&gt;Configuring tag-based access control and role assignments is done through the Pulumi Cloud console and REST API.&lt;/p&gt;
&lt;h3 id="1-create-a-custom-role-with-tag-based-rules"&gt;1. Create a custom role with tag-based rules&lt;/h3&gt;
&lt;p&gt;In Pulumi Cloud, navigate to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Access Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Roles&lt;/strong&gt; and create a new custom role. In the role configuration, add tag-based rules that define which entities the role should apply to.&lt;/p&gt;
&lt;p&gt;For example, to create a role that grants write access to all production stacks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create custom role&lt;/strong&gt; and give it a descriptive name (e.g., &amp;ldquo;Production Deployer&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;Add a permission set (e.g., Stack Write) to the role&lt;/li&gt;
&lt;li&gt;Under entity selection, choose &lt;strong&gt;Tag-based rule&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Set the condition: tag key &lt;code&gt;env&lt;/code&gt; equals &lt;code&gt;prod&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Save the role&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="2-assign-the-role-to-a-team"&gt;2. Assign the role to a team&lt;/h3&gt;
&lt;p&gt;Go to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Access Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Teams&lt;/strong&gt;, select a team, and assign your custom role. All team members immediately inherit the defined permissions.&lt;/p&gt;
&lt;h3 id="3-assign-a-role-to-an-individual-user"&gt;3. Assign a role to an individual user&lt;/h3&gt;
&lt;p&gt;For users with unique access requirements, go to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Access Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Members&lt;/strong&gt;, select a user, and assign a custom role directly.&lt;/p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Custom roles with tag-based access control"
controls
autoplay muted playsinline
loop &gt;
&lt;source src="abac-demo.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;h2 id="enforce-tagging-standards-with-pulumi-policy"&gt;Enforce tagging standards with Pulumi Policy&lt;/h2&gt;
&lt;p&gt;Tag-based access control relies on consistent tagging. If a stack is missing a tag or has an incorrect value, permissions won&amp;rsquo;t be applied as expected. &lt;a href="https://www.pulumi.com/docs/insights/policy/"&gt;Pulumi Policy&lt;/a&gt; closes this gap by letting you enforce tagging standards as a &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-groups/"&gt;preventative policy group&lt;/a&gt;, so any &lt;code&gt;pulumi up&lt;/code&gt; on a stack with missing or invalid tags is blocked before deployment. This ensures your tag-based RBAC rules always grant the correct permissions. Policy enforces the standard, RBAC enforces the access.&lt;/p&gt;
&lt;p&gt;To learn how to write policies that validate stack tags, see &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-packs/authoring/#using-stack-tags-in-policies"&gt;Using stack tags in policies&lt;/a&gt;.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Pulumi Policy currently supports tag enforcement for IaC stacks. For ESC environments and Insights accounts, tags are managed through the Pulumi Cloud console or REST API.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="availability"&gt;Availability&lt;/h2&gt;
&lt;p&gt;Tag-based access control, team role assignments, and user role assignments are available today for customers on the &lt;strong&gt;Pulumi Enterprise&lt;/strong&gt; and &lt;strong&gt;Pulumi Business Critical&lt;/strong&gt; plans. Check out our &lt;a href="https://www.pulumi.com/pricing/"&gt;pricing page&lt;/a&gt; for more details on editions and what&amp;rsquo;s included.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;With custom roles providing fine-grained permissions, tag-based rules enabling dynamic access policies, and the ability to assign roles directly to teams and users, Pulumi IAM now provides everything you need to implement automated, least-privilege access control at scale. We&amp;rsquo;re excited to see how you leverage these new capabilities to secure and streamline your cloud operations.&lt;/p&gt;
&lt;p&gt;Explore the &lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac"&gt;IAM documentation&lt;/a&gt; to get started, and share your feedback in our &lt;a href="https://github.com/pulumi/pulumi-cloud-requests/issues"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="learn-more"&gt;Learn more&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac"&gt;RBAC overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/roles"&gt;Roles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/permission-sets"&gt;Permission sets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/teams"&gt;Teams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/scopes"&gt;Scopes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/pulumi-cloud-iam-launch/"&gt;Pulumi IAM launch blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/pulumi-cloud-iam-self-hosted/"&gt;Pulumi IAM for self-hosted&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Devon Grove</author><author>Davide Massarenti</author><author>Casey Huang</author><author>Arun Loganathan</author><category>iam</category><category>rbac</category><category>security</category><category>features</category><category>pulumi-cloud</category></item><item><title>From Kubernetes Gatekeeper to Full-Stack Governance with OPA</title><link>https://www.pulumi.com/blog/kubernetes-gatekeeper-full-stack-governance-opa/</link><pubDate>Thu, 19 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/kubernetes-gatekeeper-full-stack-governance-opa/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/kubernetes-gatekeeper-full-stack-governance-opa/index.png" /&gt;
&lt;p&gt;Pulumi&amp;rsquo;s &lt;a href="https://www.openpolicyagent.org/"&gt;OPA (Open Policy Agent)&lt;/a&gt; support is now stable. The &lt;a href="https://github.com/pulumi/pulumi-policy-opa/releases/tag/v1.1.0"&gt;v1.1.0 release&lt;/a&gt; of &lt;code&gt;pulumi-policy-opa&lt;/code&gt; makes OPA/Rego a first-class policy language for Pulumi with full feature parity alongside the native TypeScript and Python policy SDKs. Write Rego policies that validate any resource Pulumi manages, across AWS, Azure, GCP, Kubernetes, and the rest of the provider ecosystem. If you already have &lt;a href="https://open-policy-agent.github.io/gatekeeper/"&gt;Kubernetes Gatekeeper&lt;/a&gt; constraint templates, a new compatibility mode lets you drop those &lt;code&gt;.rego&lt;/code&gt; files directly into a Pulumi policy pack and enforce them against your Kubernetes resources without modification.&lt;/p&gt;
&lt;h2 id="whats-in-the-stable-release"&gt;What&amp;rsquo;s in the stable release&lt;/h2&gt;
&lt;p&gt;OPA/Rego is now fully supported as a policy language for &lt;a href="https://www.pulumi.com/docs/insights/policy/"&gt;Pulumi Insights&lt;/a&gt;, with the same capabilities as the TypeScript and Python SDKs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resource and stack-level policies&lt;/strong&gt;: Validate individual resources with &lt;code&gt;deny&lt;/code&gt; and &lt;code&gt;warn&lt;/code&gt; rules, or evaluate your entire stack at once with &lt;code&gt;stack_deny&lt;/code&gt; and &lt;code&gt;stack_warn&lt;/code&gt; for cross-resource checks like relationship validation and resource count limits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enforcement levels&lt;/strong&gt;: Control how violations are handled. &lt;code&gt;mandatory&lt;/code&gt; blocks deployments, &lt;code&gt;advisory&lt;/code&gt; surfaces warnings, and &lt;code&gt;disabled&lt;/code&gt; turns rules off without removing them. Enforcement levels can be overridden per policy without modifying Rego source.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Policy configuration&lt;/strong&gt;: Pass custom parameters to policies via configuration files, with optional JSON schema validation. Configuration values are accessible in Rego as &lt;code&gt;data.config.&amp;lt;policy_name&amp;gt;.&amp;lt;key&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OPA metadata annotations&lt;/strong&gt;: Use standard OPA &lt;code&gt;# METADATA&lt;/code&gt; comments to provide titles, descriptions, and messages for your policies. These populate the policy metadata displayed in Pulumi Cloud.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Preventative and audit evaluation&lt;/strong&gt;: OPA policies work with both &lt;a href="https://www.pulumi.com/docs/insights/policy/"&gt;preventative enforcement&lt;/a&gt; during &lt;code&gt;pulumi up&lt;/code&gt; and &lt;a href="https://www.pulumi.com/blog/policy-audit-scans-for-stacks/"&gt;audit policy scans&lt;/a&gt; for continuous compliance monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can choose whichever language best fits your team. Organizations already using OPA across their toolchain can standardize on Rego for Pulumi policies, while teams preferring TypeScript or Python can continue to use those. All three languages work side by side in the same &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-groups/"&gt;policy groups&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="kubernetes-gatekeeper-compatibility"&gt;Kubernetes Gatekeeper compatibility&lt;/h2&gt;
&lt;p&gt;The headline feature of this release is native support for &lt;a href="https://open-policy-agent.github.io/gatekeeper/"&gt;Kubernetes Gatekeeper&lt;/a&gt; constraint template rules. If you&amp;rsquo;re running Gatekeeper as an admission controller in your clusters, you likely have a library of &lt;code&gt;.rego&lt;/code&gt; policies that enforce security and operational standards at admission time. With v1.1.0, those same rules can now run as Pulumi policies, catching violations during &lt;code&gt;pulumi preview&lt;/code&gt; before resources ever reach the cluster.&lt;/p&gt;
&lt;p&gt;To enable Gatekeeper compatibility, set &lt;code&gt;inputFormat: kubernetes-admission&lt;/code&gt; in your &lt;code&gt;PulumiPolicy.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Kubernetes Gatekeeper Policy Pack&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;opa&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;inputFormat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;kubernetes-admission&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this setting, Pulumi automatically wraps Kubernetes resources in the Gatekeeper &lt;a href="https://open-policy-agent.github.io/gatekeeper/website/docs/howto"&gt;AdmissionReview&lt;/a&gt; structure (&lt;code&gt;input.review.object&lt;/code&gt;, &lt;code&gt;input.review.kind&lt;/code&gt;, etc.), so your existing rules work without modification. Non-Kubernetes resources are silently skipped.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example that reuses standard Gatekeeper-style rules, requiring an &lt;code&gt;app&lt;/code&gt; label and prohibiting the &lt;code&gt;latest&lt;/code&gt; image tag:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-rego" data-lang="rego"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gatekeeper&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rego&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# METADATA&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# title: Require App Label&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# description: All Kubernetes resources must have an &amp;#34;app&amp;#34; label.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;violation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;contains&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;app&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;%s &amp;#39;%s&amp;#39; is missing required label: app&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# METADATA&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# title: Disallow Latest Tag&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# description: Container images must not use the &amp;#34;latest&amp;#34; tag.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;deny&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;contains&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;:latest&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;container &amp;#39;%s&amp;#39; uses the &amp;#39;latest&amp;#39; tag -- pin to a specific version&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These rules are identical to what you&amp;rsquo;d write for Gatekeeper. Both rule head formats are supported and can coexist: the &lt;code&gt;violation[{&amp;quot;msg&amp;quot;: msg}]&lt;/code&gt; map format and the &lt;code&gt;deny[msg]&lt;/code&gt; string format. Per-policy configuration via &lt;code&gt;input.parameters&lt;/code&gt; also works as expected. You can take a &lt;code&gt;.rego&lt;/code&gt; file from your Gatekeeper constraint templates, drop it into a Pulumi policy pack, and publish it to Pulumi Cloud to enforce automatically across your stacks.&lt;/p&gt;
&lt;p&gt;This shifts policy enforcement left. Instead of waiting for the Kubernetes API server to reject a resource at admission time, you catch the violation during &lt;code&gt;pulumi preview&lt;/code&gt;, before anything is deployed.&lt;/p&gt;
&lt;h2 id="walkthrough-reusing-policies-from-the-gatekeeper-library"&gt;Walkthrough: Reusing policies from the gatekeeper-library&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/open-policy-agent/gatekeeper-library"&gt;OPA Gatekeeper Library&lt;/a&gt; is a community-maintained collection of constraint templates covering common Kubernetes guardrails like pod security, image provenance, and resource limits. You can use these policies directly with Pulumi. Here&amp;rsquo;s an end-to-end example using the &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/allowedrepos"&gt;&lt;code&gt;allowedrepos&lt;/code&gt;&lt;/a&gt; policy to restrict which container image registries your deployments can use.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a new Kubernetes OPA policy pack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi policy new kubernetes-opa
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy the Rego source from &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/blob/master/library/general/allowedrepos/template.yaml"&gt;gatekeeper-library&lt;/a&gt; into your policy pack as &lt;code&gt;allowedrepos.rego&lt;/code&gt;. No modifications are needed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-rego" data-lang="rego"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k8sallowedrepos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;violation&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any_prefix_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;container &amp;lt;%v&amp;gt; has an invalid image repo &amp;lt;%v&amp;gt;, allowed repos are %v&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;violation&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initContainers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any_prefix_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;initContainer &amp;lt;%v&amp;gt; has an invalid image repo &amp;lt;%v&amp;gt;, allowed repos are %v&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;violation&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ephemeralContainers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any_prefix_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ephemeralContainer &amp;lt;%v&amp;gt; has an invalid image repo &amp;lt;%v&amp;gt;, allowed repos are %v&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify that your &lt;code&gt;PulumiPolicy.yaml&lt;/code&gt; has Gatekeeper compatibility enabled:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Kubernetes Gatekeeper Policy Pack&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;opa&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;inputFormat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;kubernetes-admission&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the allowed registries. Create a &lt;code&gt;policy-config.json&lt;/code&gt; file to pass the &lt;code&gt;repos&lt;/code&gt; parameter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;k8sallowedrepos&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;repos&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;gcr.io/my-company/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;docker.io/library/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Test the policy locally against a stack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi preview --policy-pack . --policy-pack-config policy-config.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Any Kubernetes deployment using an image outside the allowed registries will produce a violation at preview time, before it reaches the cluster.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Publish the pack and add it to a &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-groups/"&gt;policy group&lt;/a&gt; to enforce it across your organization:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi policy publish
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The same approach works for any policy in the gatekeeper-library: &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/containerlimits"&gt;&lt;code&gt;containerlimits&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/requiredlabels"&gt;&lt;code&gt;requiredlabels&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/disallowedtags"&gt;&lt;code&gt;disallowedtags&lt;/code&gt;&lt;/a&gt;, and others. Copy the Rego, configure parameters, and publish.&lt;/p&gt;
&lt;h2 id="part-of-the-pulumi-insights-governance-story"&gt;Part of the Pulumi Insights governance story&lt;/h2&gt;
&lt;p&gt;OPA policy support is part of the broader &lt;a href="https://www.pulumi.com/docs/insights/"&gt;Pulumi Insights&lt;/a&gt; governance platform. Insights gives you visibility and compliance across your entire cloud footprint, and OPA policies plug directly into that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Audit policy scans&lt;/strong&gt; continuously evaluate OPA policies against your &lt;a href="https://www.pulumi.com/blog/policy-audit-scans-for-stacks/"&gt;Pulumi stacks&lt;/a&gt; and discovered cloud resources, providing a compliance baseline without redeploying anything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-hosted execution&lt;/strong&gt; lets you &lt;a href="https://www.pulumi.com/blog/self-hosted-insights/"&gt;run policy evaluations on your own infrastructure&lt;/a&gt; using customer-managed workflow runners, keeping credentials and data within your network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-built compliance packs&lt;/strong&gt; for CIS, NIST, PCI DSS, and other frameworks are available alongside your custom OPA policies in the same &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-groups/"&gt;policy groups&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whether you&amp;rsquo;re enforcing policy at deployment time, scanning existing infrastructure for drift, or running continuous compliance checks, OPA policies are a native participant.&lt;/p&gt;
&lt;p&gt;&lt;img src="policy-findings.png" alt="Policy Findings dashboard in Pulumi Cloud showing compliance scores and per-stack policy evaluation results"&gt;&lt;/p&gt;
&lt;h2 id="frequently-asked-questions"&gt;Frequently asked questions&lt;/h2&gt;
&lt;h3 id="do-i-need-to-modify-my-existing-gatekeeper-rego-files"&gt;Do I need to modify my existing Gatekeeper &lt;code&gt;.rego&lt;/code&gt; files?&lt;/h3&gt;
&lt;p&gt;No. Set &lt;code&gt;inputFormat: kubernetes-admission&lt;/code&gt; in your &lt;code&gt;PulumiPolicy.yaml&lt;/code&gt; and your existing Gatekeeper constraint template rules work as-is. Pulumi handles the AdmissionReview wrapping automatically.&lt;/p&gt;
&lt;h3 id="what-happens-with-non-kubernetes-resources"&gt;What happens with non-Kubernetes resources?&lt;/h3&gt;
&lt;p&gt;When using &lt;code&gt;inputFormat: kubernetes-admission&lt;/code&gt;, non-Kubernetes resources are silently skipped during evaluation. Your Gatekeeper rules only run against Kubernetes resources.&lt;/p&gt;
&lt;h3 id="do-i-need-opa-installed-locally"&gt;Do I need OPA installed locally?&lt;/h3&gt;
&lt;p&gt;No. The &lt;code&gt;pulumi-policy-opa&lt;/code&gt; analyzer plugin embeds the OPA evaluation engine and is installed automatically by the Pulumi CLI (v3.227.0+). The standalone OPA CLI is only needed if you want to run &lt;code&gt;opa test&lt;/code&gt; against your policies independently.&lt;/p&gt;
&lt;h3 id="when-should-i-use-opa-vs-typescript-or-python-for-policies"&gt;When should I use OPA vs. TypeScript or Python for policies?&lt;/h3&gt;
&lt;p&gt;If your team already writes Rego for other tools like Gatekeeper, writing Pulumi policies in Rego keeps your policy language consistent. If your team is more comfortable with general-purpose languages or needs auto-remediation, use the TypeScript or Python SDKs.&lt;/p&gt;
&lt;p&gt;Gatekeeper constraint templates can be reused directly via the &lt;code&gt;kubernetes-admission&lt;/code&gt; input format, but other OPA integrations use different input structures, so those policies would need to be adapted to Pulumi&amp;rsquo;s resource model. All three languages work together in the same policy groups.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Templates are available for &lt;code&gt;kubernetes-opa&lt;/code&gt;, &lt;code&gt;aws-opa&lt;/code&gt;, &lt;code&gt;azure-opa&lt;/code&gt;, and &lt;code&gt;gcp-opa&lt;/code&gt; via &lt;code&gt;pulumi policy new&lt;/code&gt;. For more details, see the &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-packs/authoring/"&gt;policy authoring guide&lt;/a&gt; and the &lt;a href="https://www.pulumi.com/docs/insights/policy/"&gt;Policy as Code overview&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/docs/insights/policy/"
class="btn btn-primary"
&gt;
Get started with OPA policies
&lt;/a&gt;
&lt;a href="https://github.com/pulumi/pulumi-policy-opa" target="_blank" rel="noopener noreferrer" class="github-card"&gt;
&lt;img
src="https://opengraph.githubassets.com/1/pulumi/pulumi-policy-opa"
alt="GitHub repository: pulumi/pulumi-policy-opa"
class="github-card-image"
loading="lazy"
/&gt;
&lt;div class="github-card-content"&gt;
&lt;div class="github-card-domain"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon github-card-icon" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#b-github"/&gt;&lt;/svg&gt;
github.com/pulumi/pulumi-policy-opa
&lt;/div&gt;
&lt;/div&gt;
&lt;/a&gt;</description><author>Levi Blackstone</author><category>policy-as-code</category><category>features</category><category>opa</category><category>kubernetes</category><category>insights</category></item><item><title>Lock Down Values in Pulumi ESC with fn::final</title><link>https://www.pulumi.com/blog/esc-fn-final/</link><pubDate>Tue, 17 Mar 2026 11:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/esc-fn-final/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/esc-fn-final/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC (Environments, Secrets, and Configuration)&lt;/a&gt; allows you to compose environments by importing configuration and secrets from other environments, but this also means a child environment can silently override a value set by a parent. When that value is a security policy or a compliance setting, an accidental override can cause real problems. With the new &lt;a href="https://www.pulumi.com/docs/esc/environments/syntax/builtin-functions/fn-final/"&gt;fn::final&lt;/a&gt; built-in function, you can mark values as final, preventing child environments from overriding them. If a child environment tries to override a final value, ESC raises a warning and preserves the original value.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say you have a parent environment that sets the AWS region for all deployments. You can use &lt;code&gt;fn::final&lt;/code&gt; to ensure no child environment can change it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# project/parent-env&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;aws-region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::final&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;us-east-1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If a child environment tries to override the final value, ESC raises a &lt;code&gt;cannot override final value&lt;/code&gt; warning.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# project/child-env&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;project/parent-env&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;aws-region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;eu-west-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# raises a warning&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This evaluates to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;aws-region&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-east-1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this scenario, the ESC environment is still valid, but the final value remains unchanged.&lt;/p&gt;
&lt;h2 id="when-to-use-fnfinal"&gt;When to use fn::final&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;fn::final&lt;/code&gt; for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Security-sensitive values that shouldn&amp;rsquo;t be changed&lt;/li&gt;
&lt;li&gt;Compliance or policy settings enforced by a platform team&lt;/li&gt;
&lt;li&gt;Shared base environments where certain values must remain consistent&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;fn::final&lt;/code&gt; function is available now in all Pulumi ESC environments. For more information, check out the &lt;a href="https://www.pulumi.com/docs/esc/environments/syntax/builtin-functions/fn-final/"&gt;fn::final documentation&lt;/a&gt;!&lt;/p&gt;</description><author>Pablo Terradillos</author><author>Sean Yeh</author><category>esc</category><category>features</category></item><item><title>New: Previous Provider Version Docs in Pulumi Registry</title><link>https://www.pulumi.com/blog/previous-version-docs-are-now-available-in-the-pulumi-registry/</link><pubDate>Wed, 11 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/previous-version-docs-are-now-available-in-the-pulumi-registry/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/previous-version-docs-are-now-available-in-the-pulumi-registry/index.png" /&gt;
&lt;p&gt;The &lt;a href="https://www.pulumi.com/registry/"&gt;Pulumi Registry&lt;/a&gt; now supports browsing documentation for previous versions of first-party Pulumi providers. If you&amp;rsquo;ve ever needed to look up the API docs for an older provider version, you no longer have to dig through Git history or guess at changes — the docs are right there in the Registry. These docs also help &lt;a href="https://www.pulumi.com/docs/ai"&gt;Pulumi Neo&lt;/a&gt; and other agents more accurately assist you with your Pulumi code and operations.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;When you visit a first-party provider&amp;rsquo;s page in the Pulumi Registry, you&amp;rsquo;ll now see a version dropdown selector that lets you switch between the current version and previous versions.&lt;/p&gt;
&lt;p&gt;&lt;img src="registry-version-picker.png" alt="Version selector dropdown in the Pulumi Registry"&gt;&lt;/p&gt;
&lt;p&gt;Select a previous version from the dropdown, and the Registry loads the full API documentation for that version.&lt;/p&gt;
&lt;h2 id="whats-available"&gt;What&amp;rsquo;s available&lt;/h2&gt;
&lt;p&gt;This feature currently includes documentation for the latest release of each previous major version, going back two major versions. For example, if a provider is on v7.x, you&amp;rsquo;ll be able to view docs for the latest v6.x and v5.x releases in addition to the current version.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Head over to the &lt;a href="https://www.pulumi.com/registry/"&gt;Pulumi Registry&lt;/a&gt; and try it out. Pick any first-party provider with multiple major versions and use the version dropdown to browse its history.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;d love to hear your feedback — let us know what you think in the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt; or by opening an issue on &lt;a href="https://github.com/pulumi/registry"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/registry/"
class="btn btn-primary"
&gt;
Explore the Pulumi Registry
&lt;/a&gt;</description><author>Cam Soper</author><author>Fausto Núñez Alberro</author><category>registry</category><category>features</category></item><item><title>Pulumi Cloud Now Supports Google Sign-In</title><link>https://www.pulumi.com/blog/pulumi-cloud-now-supports-google-sign-in/</link><pubDate>Tue, 10 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-cloud-now-supports-google-sign-in/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-cloud-now-supports-google-sign-in/index.png" /&gt;
&lt;p&gt;Many developers and platform engineers already use Google accounts daily for email, cloud console access, and collaboration. Until now, signing in to Pulumi Cloud required a &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://gitlab.com/"&gt;GitLab&lt;/a&gt;, or &lt;a href="https://id.atlassian.com/"&gt;Atlassian&lt;/a&gt; account, or an email/password combination. Today, we&amp;rsquo;re adding Google as a first-class identity provider, so you can sign in to Pulumi Cloud with the same Google account you already use for everything else.&lt;/p&gt;
&lt;p&gt;Adding Google as an identity provider brings several benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use the account you already have. If your team already lives in &lt;a href="https://workspace.google.com/"&gt;Google Workspace&lt;/a&gt;, you can sign in to Pulumi Cloud with a single click, no new credentials required.&lt;/li&gt;
&lt;li&gt;Inherit your existing security policies. If you&amp;rsquo;ve already configured two-factor authentication, device management, and other protections in a Google Workspace, you can carry them over to Pulumi Cloud automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;h3 id="signing-up-or-signing-in"&gt;Signing up or signing in&lt;/h3&gt;
&lt;p&gt;On the Pulumi Cloud sign-in page, you&amp;rsquo;ll see a new &lt;strong&gt;Sign in with Google&lt;/strong&gt; button alongside the existing GitHub, GitLab, and Atlassian options. If you are a new user, select it, authenticate with your Google account, and you&amp;rsquo;re in.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;If you already have an existing Pulumi Cloud account, make sure to associate to your existing account as described in the next section.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="sign-in.png" alt="Pulumi Cloud sign-in page showing Google as an identity provider option"&gt;&lt;/p&gt;
&lt;h3 id="connecting-google-to-an-existing-account"&gt;Connecting Google to an existing account&lt;/h3&gt;
&lt;p&gt;If you already have a Pulumi Cloud account, you can link your Google identity from your account settings:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to your &lt;a href="https://app.pulumi.com/account/settings"&gt;Account Settings&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Scroll to the &lt;strong&gt;Identity providers&lt;/strong&gt; section.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Available identities&lt;/strong&gt;, select &lt;strong&gt;Connect Google&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once connected, you can use Google to sign in to your existing Pulumi Cloud account.&lt;/p&gt;
&lt;p&gt;&lt;img src="connected-identities.png" alt="Account settings showing connected identities including Google"&gt;&lt;/p&gt;
&lt;h3 id="google-sign-in-vs-saml-sso"&gt;Google sign-in vs. SAML SSO&lt;/h3&gt;
&lt;p&gt;Google sign-in lets you authenticate with Pulumi Cloud using your individual Google account. It does not enable Google as a single sign-on (SSO) identity provider for your Pulumi Cloud organization.&lt;/p&gt;
&lt;p&gt;If your team uses Google Workspace and needs centralized membership governance for Pulumi Cloud, configure &lt;a href="https://www.pulumi.com/docs/administration/access-identity/saml/gsuite/"&gt;SAML SSO with Google Workspace&lt;/a&gt; instead. SAML SSO is available on Pulumi Enterprise and Business Critical editions.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Google sign-in is available now for all new and existing Pulumi Cloud users:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;New users&lt;/strong&gt;: &lt;a href="https://app.pulumi.com/signup"&gt;Sign up with Google&lt;/a&gt; on the Pulumi Cloud sign-up page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Existing users&lt;/strong&gt;: &lt;a href="https://app.pulumi.com/account/settings"&gt;Connect your Google account&lt;/a&gt; in your account settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more details, see the &lt;a href="https://www.pulumi.com/docs/administration/organizations-teams/accounts/"&gt;Pulumi Cloud accounts documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;d love to hear your feedback. Join the conversation in the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt; or open an issue on &lt;a href="https://github.com/pulumi/pulumi-cloud-requests/issues/new/choose"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</description><author>Pablo Seibelt</author><author>Casey Huang</author><category>features</category><category>security</category><category>authentication</category><category>pulumi-cloud</category></item><item><title>Expanded Version Control Support in Pulumi Cloud</title><link>https://www.pulumi.com/blog/expanded-version-control-support/</link><pubDate>Mon, 09 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/expanded-version-control-support/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/expanded-version-control-support/index.png" /&gt;
&lt;p&gt;Your version control provider shouldn&amp;rsquo;t limit your infrastructure workflows. Pulumi Cloud now works with &lt;a href="https://www.pulumi.com/docs/version-control/github-app/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/version-control/github-app/#github-enterprise-server-support"&gt;GitHub Enterprise Server&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/version-control/azure-devops-integration/"&gt;Azure DevOps&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/version-control/gitlab/"&gt;GitLab&lt;/a&gt;. Every team gets the same &lt;a href="https://www.pulumi.com/docs/deployments/deployments/"&gt;deployment pipelines&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/deployments/deployments/review-stacks/"&gt;PR previews&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/ai/"&gt;AI-powered change summaries&lt;/a&gt; regardless of where their code lives.&lt;/p&gt;
&lt;p&gt;&lt;img src="VCS.png" alt="Add account screen showing GitHub, GitLab, and Azure DevOps as VCS options"&gt;&lt;/p&gt;
&lt;h2 id="connect-multiple-providers-and-accounts"&gt;Connect multiple providers and accounts&lt;/h2&gt;
&lt;p&gt;You can connect multiple VCS providers to a single Pulumi organization simultaneously, like GitHub, GitLab, and Azure DevOps all at once. You can also connect multiple accounts of the same provider, such as two separate GitHub organizations or two GitLab groups. This means teams that work across different repositories, providers, or organizational boundaries can manage everything from one place.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;GitHub Enterprise Server is currently limited to one connection per Pulumi organization.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="what-your-team-can-do"&gt;What your team can do&lt;/h2&gt;
&lt;h3 id="deploy-on-every-push"&gt;Deploy on every push&lt;/h3&gt;
&lt;p&gt;Connect a repository to a stack, and infrastructure deploys automatically when you push. Configure path filters to trigger only when relevant files change, and manage environment variables and secrets directly in Pulumi Cloud. No external CI/CD pipeline required.&lt;/p&gt;
&lt;h3 id="preview-changes-on-pull-requests"&gt;Preview changes on pull requests&lt;/h3&gt;
&lt;p&gt;Every pull request gets an infrastructure preview so reviewers can see exactly what will change before merging. The preview runs the same Pulumi operations your deployment would, giving your team confidence that a merge won&amp;rsquo;t break anything.&lt;/p&gt;
&lt;h3 id="neo-explains-your-changes"&gt;Neo explains your changes&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/product/neo/"&gt;Neo&lt;/a&gt; posts AI-generated summaries on your pull requests explaining what infrastructure changes mean in plain language. Reviewers who aren&amp;rsquo;t Pulumi experts can still understand the impact of a change without reading resource diffs.&lt;/p&gt;
&lt;p&gt;&lt;img src="ado-prcomments.png" alt="Neo posting an infrastructure change summary on a pull request"&gt;&lt;/p&gt;
&lt;h3 id="let-neo-open-pull-requests-for-you"&gt;Let Neo open pull requests for you&lt;/h3&gt;
&lt;p&gt;Ask Neo to make infrastructure changes and it opens pull requests directly against your connected repositories. Describe what you want in natural language, and Neo writes the code, opens the PR, and kicks off a preview, all without leaving Pulumi Cloud.&lt;/p&gt;
&lt;h3 id="detect-and-fix-drift"&gt;Detect and fix drift&lt;/h3&gt;
&lt;p&gt;Schedule &lt;a href="https://www.pulumi.com/docs/pulumi-cloud/deployments/drift/"&gt;drift detection&lt;/a&gt; to catch out-of-band changes automatically. When someone modifies infrastructure outside of your Pulumi programs, drift detection flags the difference so your team can remediate before it causes issues.&lt;/p&gt;
&lt;h3 id="secure-authentication"&gt;Secure authentication&lt;/h3&gt;
&lt;p&gt;Pulumi Cloud authenticates with your VCS provider using OIDC or OAuth so no long-lived credentials need to be stored. Short-lived tokens keep your deployment pipelines secure without manual secret rotation.&lt;/p&gt;
&lt;h3 id="set-up-new-projects-from-your-vcs"&gt;Set up new projects from your VCS&lt;/h3&gt;
&lt;p&gt;The new project wizard discovers your organizations, repositories, and branches so you can scaffold and deploy a new stack without leaving Pulumi Cloud. Pick your repo, choose a branch, and you&amp;rsquo;re ready to deploy.&lt;/p&gt;
&lt;p&gt;&lt;img src="ado-npw.png" alt="New project wizard showing repository settings"&gt;&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;An org admin configures the integration under &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Version Control&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Authorize with your VCS provider.&lt;/li&gt;
&lt;li&gt;Deploy infrastructure with first-class workflows.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For setup details, see the docs for &lt;a href="https://www.pulumi.com/docs/version-control/github-app/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/version-control/github-app/#github-enterprise-server-support"&gt;GitHub Enterprise Server&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/version-control/azure-devops-integration/"&gt;Azure DevOps&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/version-control/gitlab/"&gt;GitLab&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://app.pulumi.com/signin"
class="btn btn-primary"
target="_blank"
rel="noopener noreferrer"
&gt;
Connect your VCS
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular text-sm ml-2" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-arrow-square-out-regular"/&gt;&lt;/svg&gt;
&lt;/a&gt;</description><author>Luke Ward</author><author>Michael Fallihee</author><author>Boris Schlosser</author><author>Dan Biwer</author><category>features</category><category>pulumi-cloud</category><category>azure</category><category>github</category><category>gitlab</category></item><item><title>Now Generally Available: Store Terraform State in Pulumi Cloud</title><link>https://www.pulumi.com/blog/terraform-state-backend-pulumi-cloud/</link><pubDate>Thu, 05 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/terraform-state-backend-pulumi-cloud/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/terraform-state-backend-pulumi-cloud/index.png" /&gt;
&lt;p&gt;Platform engineering teams managing infrastructure across Terraform and Pulumi now have a way to unify state management without rewriting a single line of HCL. Starting today, Pulumi Cloud can serve as a &lt;a href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/"&gt;Terraform state backend&lt;/a&gt;, letting you store and manage Terraform state alongside your Pulumi stacks. Your team continues using the Terraform or OpenTofu CLI for day-to-day operations while gaining the benefits of Pulumi Cloud: AI-powered infrastructure management with &lt;a href="https://www.pulumi.com/docs/ai"&gt;Pulumi Neo&lt;/a&gt; — our infrastructure agent — encrypted state storage, update history, state locking, role-based access control, audit policies, and unified resource visibility through &lt;a href="https://www.pulumi.com/docs/pulumi-cloud/insights/"&gt;Insights&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This feature is now generally available.&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;Most organizations adopting Pulumi are not starting from scratch. They have years of Terraform deployments spread across teams, and migrating everything to a new IaC tool overnight is not realistic. We have heard from customers who are excited about the power of Pulumi Cloud but have had to manage migration projects before they can fully benefit from centralized visibility and governance.&lt;/p&gt;
&lt;p&gt;The Terraform state backend in Pulumi Cloud changes that equation. Instead of requiring a full code conversion before teams see value, you can migrate your state in minutes and immediately unlock Pulumi Cloud capabilities for your existing Terraform infrastructure — including Neo, Pulumi&amp;rsquo;s AI infrastructure agent. Once your Terraform state is in Pulumi Cloud, Neo can reason about those resources the same way it does for Pulumi IaC stacks: finding resources, troubleshooting issues, understanding dependencies, and writing infrastructure code PRs. Teams that prefer Terraform can keep using it, while platform engineers get a single AI-powered control plane across the entire infrastructure estate.&lt;/p&gt;
&lt;h2 id="what-you-get"&gt;What you get&lt;/h2&gt;
&lt;p&gt;When you store Terraform state in Pulumi Cloud, your Terraform-managed resources get the following added functionality:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agentic infrastructure with Neo.&lt;/strong&gt; &lt;a href="https://www.pulumi.com/docs/ai/"&gt;Neo&lt;/a&gt;, Pulumi&amp;rsquo;s AI infrastructure agent, works across your entire cloud footprint — Terraform and Pulumi IaC alike. Once your Terraform state is in Pulumi Cloud, you can ask Neo to find resources across both tools, trace dependencies that span Terraform and Pulumi stacks, troubleshoot configuration issues, and generate new infrastructure code informed by your existing resources. This means platform teams get a single AI-powered interface regardless of which IaC tool manages each piece of infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Encrypted state with update history.&lt;/strong&gt; State is encrypted in transit and at rest. Every change is tracked as a versioned checkpoint visible in the &lt;a href="https://www.pulumi.com/docs/deployments/projects-and-stacks/#stack-activity"&gt;stack activity tab&lt;/a&gt;, giving you full rollback capability. This is a common concern for teams currently storing state in S3 buckets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Automatic state locking.&lt;/strong&gt; Pulumi Cloud prevents concurrent Terraform operations from corrupting state, without requiring you to configure DynamoDB tables or other external locking mechanisms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Role-based access control.&lt;/strong&gt; Control who can read or modify each stack using &lt;a href="https://www.pulumi.com/docs/administration/access-identity/rbac/"&gt;teams and RBAC&lt;/a&gt;, applying the same access policies you use for Pulumi stacks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unified resource visibility.&lt;/strong&gt; View Terraform-managed resources alongside Pulumi-managed resources in &lt;a href="https://www.pulumi.com/docs/insights/discovery/search/"&gt;Resource Search&lt;/a&gt;. Each Terraform resource appears in the console using a &lt;code&gt;pulumi:terraform:&amp;lt;tf-type&amp;gt;&lt;/code&gt; naming convention, so you can search and filter using the attribute names you already know.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Audit policies.&lt;/strong&gt; Run &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-groups/"&gt;audit (detective) policy packs&lt;/a&gt; against your Terraform-managed stacks, including Pulumi&amp;rsquo;s &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-packs/pre-built-packs/"&gt;pre-built compliance packs&lt;/a&gt; for CIS, PCI, and more. Pulumi Cloud performs a best-effort schema mapping from Terraform resource shapes to Pulumi provider equivalents, so existing policy packs work without modification in most cases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stack outputs and references.&lt;/strong&gt; Terraform root module outputs are automatically mapped to Pulumi &lt;a href="https://www.pulumi.com/docs/iac/concepts/stacks/#outputs"&gt;stack outputs&lt;/a&gt;, making them available via &lt;a href="https://www.pulumi.com/docs/iac/concepts/stacks/#stackreferences"&gt;stack references&lt;/a&gt; and the &lt;a href="https://www.pulumi.com/docs/esc/integrations/infrastructure/pulumi-iac/pulumi-stacks/"&gt;&lt;code&gt;pulumi-stacks&lt;/code&gt; ESC provider&lt;/a&gt;. This is useful for sharing foundational infrastructure like VPC IDs or DNS zones between Terraform and Pulumi stacks, and for incremental migrations where legacy infrastructure stays in Terraform while new stacks are written in Pulumi.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Pulumi Cloud implements the &lt;a href="https://developer.hashicorp.com/terraform/language/backend/remote"&gt;Terraform remote backend API&lt;/a&gt;. You point the Terraform CLI at Pulumi Cloud using the standard &lt;code&gt;backend &amp;quot;remote&amp;quot;&lt;/code&gt; configuration block, and no changes to your Terraform code or workflow are required.&lt;/p&gt;
&lt;p&gt;Each Terraform workspace maps to a Pulumi stack. The workspace name follows the convention &lt;code&gt;&amp;lt;project&amp;gt;_&amp;lt;stack&amp;gt;&lt;/code&gt;. For example, &lt;code&gt;networking_prod&lt;/code&gt; creates a stack named &lt;code&gt;prod&lt;/code&gt; in the &lt;code&gt;networking&lt;/code&gt; project.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Migration from S3, Azure Blob, GCS, local backends, or HCP Terraform (Terraform Cloud) takes minutes and is documented in the &lt;a href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/"&gt;Terraform state backend guide&lt;/a&gt;. From S3, Azure Blob, GCS, or local state, back up your state, update your backend block to point to Pulumi Cloud, set &lt;code&gt;TF_TOKEN_api_pulumi_com&lt;/code&gt;, and run &lt;code&gt;terraform init -migrate-state&lt;/code&gt;. From HCP Terraform, export state manually and push it to Pulumi Cloud.&lt;/p&gt;
&lt;p&gt;Each Terraform resource stored in Pulumi Cloud counts as a resource under management, the same as a Pulumi-managed resource. See the &lt;a href="https://www.pulumi.com/pricing/"&gt;pricing page&lt;/a&gt; for details.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/"
class="btn btn-primary"
&gt;
Store Terraform State in Pulumi Cloud
&lt;/a&gt;
&lt;p&gt;If you have questions or feedback, join us in the &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; or open an issue on &lt;a href="https://github.com/pulumi/pulumi"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</description><author>Claire Gaestel</author><category>releases</category><category>features</category><category>terraform</category><category>pulumi-cloud</category><category>infrastructure-as-code</category></item><item><title>Now GA: Up to 20x Faster Pulumi Operations for Everyone</title><link>https://www.pulumi.com/blog/journaling-ga/</link><pubDate>Thu, 05 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/journaling-ga/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/journaling-ga/index.png" /&gt;
&lt;p&gt;In January, we &lt;a href="https://www.pulumi.com/blog/journaling/"&gt;introduced a major performance enhancement for Pulumi Cloud&lt;/a&gt; through a fundamental change to how Pulumi manages state that speeds up operations by up to 20x. After a staged rollout across many organizations, &lt;strong&gt;it is now enabled by default for every Pulumi Cloud operation&lt;/strong&gt;. No opt-in required—just use Pulumi CLI v3.225.0+ with Pulumi Cloud. The improvement applies to &lt;code&gt;pulumi up&lt;/code&gt;, &lt;code&gt;pulumi destroy&lt;/code&gt;, and &lt;code&gt;pulumi refresh&lt;/code&gt;; &lt;code&gt;pulumi preview&lt;/code&gt; does not modify state, so it is unchanged.&lt;/p&gt;
&lt;h2 id="what-this-means-for-you"&gt;What this means for you&lt;/h2&gt;
&lt;p&gt;First and foremost, nothing about how you work with &lt;code&gt;pulumi&lt;/code&gt; needs to change. Your updates now benefit from better parallelism and should thus complete faster. Before this change, &lt;code&gt;pulumi&lt;/code&gt; always saved a full snapshot to the cloud, so the current state could always be recovered if something goes wrong. With journaling, we now only send the state of each operation, which allows us to send these updates in parallel, as long as resources are not related to each other. For the full deep dive, see the blog post linked above.&lt;/p&gt;
&lt;h2 id="production-results"&gt;Production results&lt;/h2&gt;
&lt;p&gt;Since January, we&amp;rsquo;ve had many early adopters of journaling. This helped us shake out one final bug on the server side, and journaling has been stable since then. With that we feel confident in rolling this out to all our users.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve also gathered some real-world data on how journaling is performing. The data from the preview period shows some significant improvements for update times. For stacks with fewer than 100 resources, the median improvement is 25.3%, while the p90 improvement is 75.2%, and we&amp;rsquo;ve seen a p99 improvement of up to 92.6% Meanwhile, for larger stacks, the median improvement is 60.2%. We need more data for stacks with more than 100 resources, we will update this blog once that comes in.&lt;/p&gt;
&lt;p&gt;This data already shows the expected significant improvement in update times, especially for larger stacks, though the improvements strongly depend on the shape and type of resources that are being set up. Stacks with many resources, that are quick to update benefit more than smaller stacks with slower to set up resources. For more numbers see also the &lt;a href="https://www.pulumi.com/blog/journaling/#benchmarks"&gt;Benchmarks section in the previous blog post&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="what-you-need-to-do"&gt;What you need to do&lt;/h2&gt;
&lt;p&gt;While this was an opt-in process using the &lt;code&gt;PULUMI_ENABLE_JOURNALING&lt;/code&gt; environment variable, this opt-in is no longer required. Just upgrade your Pulumi CLI to v3.225.0+ and use the Pulumi Cloud backend, and journaling will automatically speed up your updates.&lt;/p&gt;
&lt;p&gt;If you encounter any issues, reach out on the &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; or through &lt;a href="https://support.pulumi.com/hc/en-us"&gt;Pulumi Support&lt;/a&gt;. You can also set the &lt;code&gt;PULUMI_DISABLE_JOURNALING=true&lt;/code&gt; env variable to opt out of journaling.&lt;/p&gt;</description><author>Thomas Gummerer</author><author>Pat Gavlin</author><category>performance</category><category>pulumi-cloud</category><category>features</category><category>releases</category></item><item><title>Run Pulumi Insights on Your Own Infrastructure</title><link>https://www.pulumi.com/blog/self-hosted-insights/</link><pubDate>Mon, 02 Mar 2026 00:06:00 -0700</pubDate><guid>https://www.pulumi.com/blog/self-hosted-insights/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/self-hosted-insights/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/insights/"&gt;Pulumi Insights&lt;/a&gt; gives you visibility and governance across your entire cloud footprint: &lt;strong&gt;discovery scans&lt;/strong&gt; catalog every resource in your cloud accounts, and &lt;strong&gt;policy evaluations&lt;/strong&gt; continuously enforce compliance against those resources. Until now, Insights workflows ran exclusively on Pulumi-hosted infrastructure. That works well for many teams, but enterprises with strict data residency requirements, private network constraints, or regulatory obligations need to run this work in their own environments. Today, Pulumi Insights supports &lt;a href="https://www.pulumi.com/docs/deployments/deployments/customer-managed-agents/"&gt;customer-managed workflow runners&lt;/a&gt; for both SaaS Pulumi Cloud and &lt;a href="https://www.pulumi.com/docs/administration/self-hosting/"&gt;self-hosted Pulumi Cloud&lt;/a&gt; installations.&lt;/p&gt;
&lt;h2 id="insights-at-a-glance"&gt;Insights at a glance&lt;/h2&gt;
&lt;p&gt;Insights provides two complementary capabilities that together form a governance lifecycle for your cloud infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Discovery&lt;/strong&gt; scans cloud accounts across &lt;a href="https://aws.amazon.com/"&gt;AWS&lt;/a&gt;, &lt;a href="https://azure.microsoft.com/"&gt;Azure&lt;/a&gt;, &lt;a href="https://cloud.google.com/"&gt;GCP&lt;/a&gt;, and more to catalog every resource regardless of how it was provisioned: Pulumi, &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt;, &lt;a href="https://aws.amazon.com/cloudformation/"&gt;CloudFormation&lt;/a&gt;, or manual creation. Once cataloged, you can search, filter, group, and &lt;a href="https://www.pulumi.com/docs/insights/discovery/data-export/"&gt;export&lt;/a&gt; your resource data. You can also &lt;a href="https://www.pulumi.com/docs/insights/discovery/visual-import/"&gt;import&lt;/a&gt; unmanaged resources into Pulumi to bring them under IaC management.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Policy&lt;/strong&gt; enforces compliance with policy-as-code written in &lt;a href="https://www.typescriptlang.org/"&gt;TypeScript&lt;/a&gt; or &lt;a href="https://www.python.org/"&gt;Python&lt;/a&gt;. Pulumi ships &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-packs/pre-built-packs/"&gt;pre-built compliance packs&lt;/a&gt; for CIS, NIST, PCI DSS, HITRUST, and other frameworks so you can start evaluating without writing any code. &lt;a href="https://www.pulumi.com/docs/insights/policy/policy-groups/#audit-policy-groups"&gt;Audit policy groups&lt;/a&gt; continuously evaluate all discovered resources and IaC stacks, while preventative policies block non-compliant deployments before they reach production.&lt;/p&gt;
&lt;p&gt;This enables you to map out your cloud estate, evaluate compliance, and then remediate any issues uncovered by policy.&lt;/p&gt;
&lt;h2 id="why-self-hosted"&gt;Why self-hosted?&lt;/h2&gt;
&lt;p&gt;Running Insights on your own infrastructure with &lt;a href="https://www.pulumi.com/docs/deployments/deployments/customer-managed-agents/"&gt;customer-managed workflow runners&lt;/a&gt; gives you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data residency&lt;/strong&gt;: Scan execution and policy evaluation run entirely within your private network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private infrastructure access&lt;/strong&gt;: Scan resources in VPCs and environments that are not accessible from the public internet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compliance&lt;/strong&gt;: Cloud provider credentials can stay internal to your network, meeting regulatory requirements for credential handling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible hosting&lt;/strong&gt;: Run workflow runners on any environment that meets your needs, including Linux, macOS, &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;, and &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Customer-managed workflow runners are lightweight agents that poll Pulumi Cloud for pending work, execute it locally, and report results back. You can configure runners to handle specific workflow types: discovery scans, policy evaluations, deployments, or all three.&lt;/p&gt;
&lt;p&gt;This works identically whether you use SaaS Pulumi Cloud or a self-hosted installation. The runner communicates with the Pulumi Cloud API over HTTPS, so no inbound connectivity is required, making it well suited to run in restricted network environments.&lt;/p&gt;
&lt;p&gt;Under the hood, this is powered by a distributed work scheduling system that routes activities to the right runner pool, handles lease-based execution, and recovers automatically from failures. For a deep dive on the architecture, see &lt;a href="https://www.pulumi.com/blog/how-we-built-a-distributed-work-scheduling-system-for-pulumi-cloud/"&gt;How We Built a Distributed Work Scheduling System for Pulumi Cloud&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If your team already uses customer-managed workflow runners for &lt;a href="https://www.pulumi.com/docs/deployments/"&gt;Pulumi Deployments&lt;/a&gt;, your existing runner pools can handle Insights workflows with no additional infrastructure.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Self-hosted Insights is available on the Business Critical edition of Pulumi Cloud. To learn more or get set up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/insights/self-hosted/"&gt;Self-hosted Insights documentation&lt;/a&gt; — configuration and setup for discovery scans and audit policy evaluations on your own infrastructure&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/deployments/deployments/customer-managed-agents/"&gt;Customer-managed workflow runners&lt;/a&gt; — runner installation, configuration reference, and pool management&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/insights/"&gt;Insights &amp;amp; Governance overview&lt;/a&gt; — full documentation for discovery and policy capabilities&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/contact/?form=sales"&gt;Contact sales&lt;/a&gt; to enable self-hosted Insights for your organization&lt;/li&gt;
&lt;/ul&gt;</description><author>Levi Blackstone</author><category>insights</category><category>features</category><category>pulumi-cloud</category><category>policy-as-code</category></item><item><title>How We Built a Distributed Work Scheduling System for Pulumi Cloud</title><link>https://www.pulumi.com/blog/how-we-built-a-distributed-work-scheduling-system-for-pulumi-cloud/</link><pubDate>Thu, 26 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/how-we-built-a-distributed-work-scheduling-system-for-pulumi-cloud/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/how-we-built-a-distributed-work-scheduling-system-for-pulumi-cloud/index.png" /&gt;
&lt;p&gt;Pulumi Cloud orchestrates a growing number of workflow types: &lt;a href="https://www.pulumi.com/docs/deployments/"&gt;Deployments&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/insights/"&gt;Insights&lt;/a&gt; discovery scans, and &lt;a href="https://www.pulumi.com/docs/insights/policy/"&gt;policy evaluations&lt;/a&gt;. Some of that work runs on Pulumi&amp;rsquo;s infrastructure, and some of it runs on yours via &lt;a href="https://www.pulumi.com/docs/deployments/deployments/customer-managed-agents/"&gt;customer-managed workflow runners&lt;/a&gt;. We needed a scheduling system that could handle all of these workflow types reliably across both environments. In this post, we&amp;rsquo;ll take a look at the system we built.&lt;/p&gt;
&lt;h2 id="where-we-started"&gt;Where we started&lt;/h2&gt;
&lt;p&gt;For our first workflow integration, Deployments, scheduling wasn&amp;rsquo;t too complicated. A deployment was queued, a worker picked it up, and it ran. The queue was purpose-built for deployments, and it worked well for that single use case. Over time, we added more sophisticated logic to handle retries, ordering, rate limiting, observability, and more.&lt;/p&gt;
&lt;p&gt;With the launch of Insights, the number of workflow types grew. Now Pulumi Cloud manages discovery scans to catalog cloud resources and runs audit policy evaluations to continuously verify compliance. While these workflows share similarities, each type needed its own scheduling, retry logic, and failure handling.&lt;/p&gt;
&lt;p&gt;Later we added the option for customers to run workflows on their own infrastructure using &lt;a href="https://www.pulumi.com/docs/deployments/deployments/customer-managed-agents/"&gt;customer-managed workflow runners&lt;/a&gt;. As the complexity of these requirements grew, we knew that our initial approach for Deployments wasn&amp;rsquo;t going to scale. We needed a single system that could schedule any type of work, route it to the right place, and handle the messy reality of distributed execution: crashes, network failures, rate limits, and retries.&lt;/p&gt;
&lt;p&gt;We call this the &lt;strong&gt;background activity system&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="why-not-use-an-off-the-shelf-queue"&gt;Why not use an off-the-shelf queue?&lt;/h2&gt;
&lt;p&gt;Why build this instead of using Amazon SQS, RabbitMQ, or one of the many existing queue libraries? We considered these options but chose to build our own for a few reasons.&lt;/p&gt;
&lt;p&gt;Pulumi Cloud supports &lt;a href="https://www.pulumi.com/docs/administration/self-hosting/"&gt;self-hosted installations&lt;/a&gt;, including air-gapped environments. We intentionally minimize external dependencies so that self-hosted customers don&amp;rsquo;t have to stand up additional infrastructure. A system built on an external queue works fine for our hosted service, but it means self-hosted customers would need to provide a compatible backend. By building on top of the database we already require, we avoid adding another system to maintain.&lt;/p&gt;
&lt;p&gt;More importantly, queueing is only part of the problem. What we actually need is &lt;em&gt;scheduling with durability&lt;/em&gt;. This means ensuring that remote workers don&amp;rsquo;t lose activities on restart, priority so that urgent work gets compute resources first, constraints like &amp;ldquo;only so many scans per org at a time,&amp;rdquo; structured logging for observability, and checkpointing so that long-running operations can resume after a failure.&lt;/p&gt;
&lt;p&gt;These features can be layered onto a generic queue library but can require more code than implementing them directly. For example, priority queues are often implemented with multiple ranked queues, but this breaks single-activity-at-a-time constraints. A second queue wouldn&amp;rsquo;t see a job already running in the first one. There&amp;rsquo;s no way for producers in a distributed system to coordinate across the queues without support in the queuing system itself.&lt;/p&gt;
&lt;p&gt;Capacity management is another area where generic queues fall short. Distributed systems need to respond dynamically to slowdowns, network interruptions, and rate limits from downstream services. These are common low-level details that every workflow type needs, and building them into the scheduling layer means individual handlers don&amp;rsquo;t have to solve them independently.&lt;/p&gt;
&lt;p&gt;We also need structured logging that works everywhere, including on customer-managed runners behind firewalls where centralized logging services aren&amp;rsquo;t accessible.&lt;/p&gt;
&lt;p&gt;Building this ourselves gave us a system that works with existing infrastructure and handles these requirements natively.&lt;/p&gt;
&lt;h2 id="design-constraints"&gt;Design constraints&lt;/h2&gt;
&lt;p&gt;With that context, here are some of the constraints that shaped the design:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pull-only agents.&lt;/strong&gt; Customer-managed workflow runners live behind NATs, corporate proxies, and air-gapped networks. They can&amp;rsquo;t accept inbound connections, so all communication has to be agent-initiated.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mixed execution environments.&lt;/strong&gt; The same system needs to work for Pulumi-hosted workers (with direct access to internal systems) and customer-managed runners (communicating entirely over REST). We didn&amp;rsquo;t want to maintain two separate code paths.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Different workflow types.&lt;/strong&gt; Deployments, Insights scans, and audit policy evaluations have different payloads and execution semantics, but they all need the same scheduling guarantees: exactly-once execution, automatic retries, failure recovery, and observability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic fault tolerance.&lt;/strong&gt; Agents crash, networks drop, and machines get recycled by autoscalers. The system needs to detect these failures and recover without needing a person to step in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extensibility.&lt;/strong&gt; We knew we&amp;rsquo;d keep adding workflow types. Adding a new one should mean writing a handler and registering it, not building new infrastructure.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-background-activity"&gt;The background activity&lt;/h2&gt;
&lt;p&gt;At the center of the system is the &lt;strong&gt;background activity&lt;/strong&gt;, a persistent, typed work unit. Each activity includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;type discriminator&lt;/strong&gt; that identifies what kind of work it represents (e.g., &amp;ldquo;insights-discovery&amp;rdquo; or &amp;ldquo;policy-evaluation&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;payload&lt;/strong&gt; specific to that type, containing whatever data the handler needs&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;routing context&lt;/strong&gt; that determines which runner pool should execute it&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scheduling metadata&lt;/strong&gt; like priority, activation time, and retry configuration&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;status&lt;/strong&gt; tracking where the activity is in its lifecycle&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The type discriminator makes this system polymorphic. The scheduling engine doesn&amp;rsquo;t need to know what&amp;rsquo;s inside the payload. It moves activities through their lifecycle and delegates the actual work to a type-specific handler.&lt;/p&gt;
&lt;h3 id="the-state-machine"&gt;The state machine&lt;/h3&gt;
&lt;p&gt;Every activity follows the same lifecycle regardless of type:&lt;/p&gt;
&lt;pre class="mermaid"&gt;
---
config:
flowchart:
curve: linear
---
graph LR
Start(( )) --&amp;gt;|Created| Ready
Ready --&amp;gt;|Leased| Pending
Pending --&amp;gt;|Started| Executing
Executing --&amp;gt;|Success| Completed
Completed --&amp;gt; End(( ))
Executing --&amp;gt;|Error| Failed
Failed --&amp;gt; End
Executing --&amp;gt;|Canceled| Canceled
Canceled --&amp;gt; End
Executing --&amp;gt;|Dependencies| Waiting
Waiting --&amp;gt;|Unblocked| Ready
Pending --&amp;gt;|Lease expired| Restarting
Executing --&amp;gt;|Lease expired| Restarting
Restarting --&amp;gt;|Re-lease| Ready
style Start fill:#000,stroke:#000,color:#000
style End fill:#000,stroke:#000,color:#000
&lt;/pre&gt;
&lt;p&gt;The states fall into two groups:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Running states&lt;/strong&gt; (work is in flight or can be resumed):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ready&lt;/strong&gt;: queued and eligible to be claimed by a worker&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pending&lt;/strong&gt;: claimed by a worker, execution about to start&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Executing&lt;/strong&gt;: actively running on a worker&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Waiting&lt;/strong&gt;: parked, blocked on one or more dependency activities&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restarting&lt;/strong&gt;: recovered after a worker failure, ready to be re-claimed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Terminal states&lt;/strong&gt; (work is done):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Completed&lt;/strong&gt;, &lt;strong&gt;Failed&lt;/strong&gt;, &lt;strong&gt;Canceled&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;New workflow types get these features automatically: scheduling, retries, dependency management, and observability.&lt;/p&gt;
&lt;h2 id="leases-distributed-execution-without-coordination"&gt;Leases: distributed execution without coordination&lt;/h2&gt;
&lt;p&gt;A central challenge of any distributed work queue is preventing double-execution. If two agents try to execute the same activity simultaneously, you get duplicate work and data corruption. A central coordinator can solve this, but it becomes a single point of failure.&lt;/p&gt;
&lt;p&gt;We use lease-based optimistic concurrency instead. This is a well-known pattern, adapted here for long-running, stateful workflows.&lt;/p&gt;
&lt;h3 id="how-it-works"&gt;How it works&lt;/h3&gt;
&lt;p&gt;When an agent is ready for new work, it asks the service to &lt;strong&gt;lease&lt;/strong&gt; an activity. The service atomically selects the highest-priority ready activity, assigns a lease token with an expiration time, and transitions the activity to &lt;code&gt;Pending&lt;/code&gt;. No other agent can claim the same activity.&lt;/p&gt;
&lt;pre class="mermaid"&gt;
sequenceDiagram
participant Agent
participant Service
Agent-&amp;gt;&amp;gt;Service: Poll for work
Note right of Service: Select highest-priority&amp;lt;br/&amp;gt;Ready activity
Note right of Service: Atomically set lease&amp;lt;br/&amp;gt;token + expiration
Service-&amp;gt;&amp;gt;Agent: Lease (token, expiration)
Agent-&amp;gt;&amp;gt;Service: Begin execution
Note right of Service: Transition to Executing
Note over Agent: Work in progress...
Agent-&amp;gt;&amp;gt;Service: Renew lease
Service-&amp;gt;&amp;gt;Agent: New expiration
Note over Agent: Work continues...
Agent-&amp;gt;&amp;gt;Service: Complete (token, result)
Note right of Service: Transition to Completed&amp;lt;br/&amp;gt;Archive activity
Service-&amp;gt;&amp;gt;Agent: Acknowledged
&lt;/pre&gt;
&lt;p&gt;While executing, the agent periodically &lt;strong&gt;renews&lt;/strong&gt; its lease to signal that it&amp;rsquo;s still working. If the agent crashes, loses network connectivity, or is terminated, it stops renewing. Once the lease expires, the service transitions the activity to &lt;code&gt;Restarting&lt;/code&gt;, making it available for another agent to claim.&lt;/p&gt;
&lt;pre class="mermaid"&gt;
sequenceDiagram
participant A as Agent A
participant S as Service
participant B as Agent B
A-&amp;gt;&amp;gt;S: Lease activity
S-&amp;gt;&amp;gt;A: Token + expiration
Note over A: Executing...
A--xS: Agent A crashes
Note right of S: Lease expires
Note right of S: Transition → Restarting
B-&amp;gt;&amp;gt;S: Poll for work
Note right of S: Lease to Agent B&amp;lt;br/&amp;gt;Transition → Pending
S-&amp;gt;&amp;gt;B: Token + expiration
Note over B: Agent B continues execution
&lt;/pre&gt;
&lt;p&gt;The service doesn&amp;rsquo;t need to explicitly coordinate between workers because leases are acquired using atomic database operations. The lease expiration is the failure detector; if a lease expires, then the work needs to be rescheduled.&lt;/p&gt;
&lt;h2 id="routing-work-to-the-right-runner-pool"&gt;Routing work to the right runner pool&lt;/h2&gt;
&lt;p&gt;Pulumi Cloud supports multiple &lt;a href="https://www.pulumi.com/docs/deployments/deployments/customer-managed-agents/"&gt;workflow runner pools&lt;/a&gt;. An organization might have one pool for production in &lt;code&gt;us-east-1&lt;/code&gt;, another for staging in &lt;code&gt;eu-west-1&lt;/code&gt;, and use Pulumi-hosted runners for development. Work needs to reach the right pool.&lt;/p&gt;
&lt;p&gt;Each activity carries a &lt;strong&gt;routing context&lt;/strong&gt; that identifies which runner pool should execute it. When a runner polls for work, it filters by its own pool identifier so that it only sees activities meant for it.&lt;/p&gt;
&lt;p&gt;We use prefix matching for this filtering. A runner matches activities whose context starts with its pool&amp;rsquo;s identifier. This means the service can use hierarchical contexts (e.g., &lt;code&gt;pool-abc/insights/scan-123&lt;/code&gt;) and runners will still match on the pool prefix. Cleanup is also straightforward; when a runner pool is deleted, all activities with that context prefix are bulk-canceled.&lt;/p&gt;
&lt;p&gt;This routing mechanism works the same way regardless of workflow type, and adding a new workflow type doesn&amp;rsquo;t require changes to the routing layer.&lt;/p&gt;
&lt;h2 id="dependencies-and-multi-step-workflows"&gt;Dependencies and multi-step workflows&lt;/h2&gt;
&lt;p&gt;Some workflows are naturally multi-step. An Insights discovery scan might discover resources that then need policy evaluation. Rather than building a separate orchestration engine, we built dependency management into the activity system.&lt;/p&gt;
&lt;p&gt;An activity can declare a &lt;strong&gt;dependency set&lt;/strong&gt;: a list of other activities that must complete before it can run. A dependent activity enters the &lt;code&gt;Waiting&lt;/code&gt; state when created. As its dependencies complete, the system checks whether all prerequisites are satisfied. When the last one finishes, the waiting activity transitions to &lt;code&gt;Ready&lt;/code&gt; and enters the scheduling queue.&lt;/p&gt;
&lt;pre class="mermaid"&gt;
graph TD
A[&amp;#34;Insights Discovery&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;Executing&amp;lt;/b&amp;gt;&amp;#34;] --&amp;gt;|depends on| B[&amp;#34;Policy Evaluation&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;Waiting&amp;lt;/b&amp;gt;&amp;#34;]
A --&amp;gt;|completes| C[&amp;#34;Insights Discovery&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;Completed&amp;lt;/b&amp;gt;&amp;#34;]
C --&amp;gt;|triggers| D[&amp;#34;Policy Evaluation&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;Ready&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;(auto-scheduled)&amp;#34;]
&lt;/pre&gt;
&lt;p&gt;This gives us a lightweight &lt;a href="https://en.wikipedia.org/wiki/Directed_acyclic_graph"&gt;DAG&lt;/a&gt; of work without requiring a separate workflow engine. Dependent activities get the same guarantees as any other activity: lease-based execution, automatic recovery, and observability.&lt;/p&gt;
&lt;h2 id="two-execution-modes-one-interface"&gt;Two execution modes, one interface&lt;/h2&gt;
&lt;p&gt;This is where the design really pays off for customer-managed runners. The system supports two execution modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Direct mode&lt;/strong&gt; runs in-process alongside the Pulumi Cloud service. Workers have low-latency access to internal systems and can process activities with minimal overhead. This is what Pulumi-hosted runners use.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote mode&lt;/strong&gt; communicates over REST APIs. The runner polls for activities, leases them, executes work locally, and reports results back over HTTP. This is what customer-managed runners use. No database access, no internal network access, no inbound connectivity required.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both modes share the same handler interface so that a workflow handler doesn&amp;rsquo;t need to know where it&amp;rsquo;s running. Whether it&amp;rsquo;s running on Pulumi&amp;rsquo;s hosted infrastructure or on a customer&amp;rsquo;s Kubernetes cluster, the handler simply processes the payload and reports a result.&lt;/p&gt;
&lt;h2 id="putting-it-all-together"&gt;Putting it all together&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s walk through a concrete example. A user wants to run an Insights discovery scan on an AWS account using a customer-managed workflow runner.&lt;/p&gt;
&lt;pre class="mermaid"&gt;
sequenceDiagram
participant User
participant PC as Pulumi Cloud
participant Runner as Workflow Runner&amp;lt;br/&amp;gt;(Customer Infrastructure)
User-&amp;gt;&amp;gt;PC: 1. Configure Insights scan&amp;lt;br/&amp;gt;for runner pool
Note right of PC: 2. Create background activity&amp;lt;br/&amp;gt;type: insights-discovery&amp;lt;br/&amp;gt;context: runner-pool-xyz&amp;lt;br/&amp;gt;status: Ready
Runner-&amp;gt;&amp;gt;PC: 3. Poll for work (filtered by pool)
PC-&amp;gt;&amp;gt;Runner: 4. Lease activity (token + expiration)
Runner-&amp;gt;&amp;gt;PC: 5. Initialize workflow
PC-&amp;gt;&amp;gt;Runner: Return cloud credentials + job token
Note over Runner: 6. Execute scan locally&amp;lt;br/&amp;gt;(talks directly to cloud APIs —&amp;lt;br/&amp;gt;credentials are used only on&amp;lt;br/&amp;gt;the runner)
Runner-&amp;gt;&amp;gt;PC: 7. Renew lease
Note right of PC: Extend expiration
Runner-&amp;gt;&amp;gt;PC: 8. Report completion
Note right of PC: 9. Mark completed&amp;lt;br/&amp;gt;Archive activity
Note right of PC: 10. Unblock dependent activities&amp;lt;br/&amp;gt;(e.g., policy evaluation)
&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;A user configures an AWS account for Insights scanning in Pulumi Cloud and assigns it to a workflow runner pool.&lt;/li&gt;
&lt;li&gt;Pulumi Cloud creates a background activity with the type set to insights discovery, the routing context set to the runner pool, and the payload containing the account configuration.&lt;/li&gt;
&lt;li&gt;A customer-managed workflow runner polling that pool detects new work.&lt;/li&gt;
&lt;li&gt;The runner leases the activity, acquiring an exclusive lock via the lease token.&lt;/li&gt;
&lt;li&gt;The runner initializes the workflow, receiving any required cloud provider credentials (e.g., resolved from &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC (Environments, Secrets, and Configuration)&lt;/a&gt;) and a job token from Pulumi Cloud.&lt;/li&gt;
&lt;li&gt;The runner executes the scan locally on the customer&amp;rsquo;s infrastructure, talking directly to the cloud provider APIs.&lt;/li&gt;
&lt;li&gt;During execution, the runner periodically renews its lease to signal liveness.&lt;/li&gt;
&lt;li&gt;The scan completes, and the runner reports the result back to Pulumi Cloud.&lt;/li&gt;
&lt;li&gt;The service marks the activity as completed and archives it.&lt;/li&gt;
&lt;li&gt;If a dependent policy evaluation activity was waiting on this scan, it automatically transitions to &lt;code&gt;Ready&lt;/code&gt; and enters the scheduling queue, where another runner in the pool can pick it up.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This flow works the same way whether the runner is hosted by Pulumi or by the customer. The only difference is whether the execution mode is direct or remote.&lt;/p&gt;
&lt;h2 id="retries-and-scheduling"&gt;Retries and scheduling&lt;/h2&gt;
&lt;p&gt;Failures are expected in distributed systems. The background activity system handles them at several levels:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lease expiration&lt;/strong&gt; covers hard failures like agent crashes, network partitions, and machine terminations. If a lease expires, the activity moves to &lt;code&gt;Restarting&lt;/code&gt;, and is available for another agent to pick up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handler-controlled retries&lt;/strong&gt; cover soft failures like transient API errors and rate limits. A handler can request a reschedule with a delay, putting the activity back in &lt;code&gt;Ready&lt;/code&gt; with a future activation time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic retries&lt;/strong&gt; provide a configurable retry budget per activity. Each activity can specify how many times it should be retried and the delay between attempts, preventing runaway retry loops.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Priority scheduling&lt;/strong&gt; ensures urgent work gets processed first. Higher-priority activities are leased before lower-priority ones, even if the lower-priority activity has been waiting longer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lease renewal during slowdowns&lt;/strong&gt; keeps the activity alive without blocking other work, even if a downstream service is slow. The agent continues renewing its lease while it waits, and the scheduler remains free to assign other activities to other agents.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="observability"&gt;Observability&lt;/h2&gt;
&lt;p&gt;Every activity generates a structured log of its execution, including timestamps, severity levels, and code context. Logs are stored with the activity record and are accessible via an API and admin tooling.&lt;/p&gt;
&lt;p&gt;This is especially useful for customer-managed runners, where the service can&amp;rsquo;t directly observe the execution environment. The structured log gives operators visibility into the execution context, even when the runner is behind a firewall. Handlers can also use these logs as a progress journal, encoding checkpoints that allow a restarted activity to pick up where it left off rather than starting from scratch.&lt;/p&gt;
&lt;p&gt;Retention policies are configurable per organization and per workflow type. Completed activities can be retained for auditing or purged to manage storage, and failed activities are typically retained longer for debugging.&lt;/p&gt;
&lt;h2 id="what-we-learned"&gt;What we learned&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A generic system pays off quickly.&lt;/strong&gt; Our initial instinct was to build targeted solutions for each workflow type. Investing in a generic activity system required more upfront design work, but now adding a new workflow type requires a fraction of the effort it would take otherwise. New workflows ship with full scheduling, retry, and observability support from day one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Leases handle many failure modes.&lt;/strong&gt; We evaluated several approaches for distributed work coordination, including message queues with explicit acknowledgment and coordinator-based assignment. The lease model works well because all failure modes are handled through timeouts. If an agent is running as expected, it renews. If it isn&amp;rsquo;t, the lease expires.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Keeping the execution paths symmetric requires discipline.&lt;/strong&gt; Making the hosted and self-hosted paths share the same handler interface was a deliberate choice. It would be easy to add shortcuts for the hosted path that bypass the remote API, but resisting that temptation means that features work for both cases automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The hard part isn&amp;rsquo;t running the work.&lt;/strong&gt; Running a scan or a deployment is straightforward once you have the right credentials. The real complexity is in everything around the execution: scheduling, routing, leasing, retrying, resolving dependencies, and cleaning up. These operational concerns aren&amp;rsquo;t visible to users, but they are essential to providing a reliable experience.&lt;/p&gt;
&lt;h2 id="wrapping-it-up"&gt;Wrapping it up&lt;/h2&gt;
&lt;p&gt;Today this system powers deployments, Insights discovery scans, and policy evaluations across both Pulumi Cloud and customer-managed infrastructure. The architecture is general enough that every new workflow type we add inherits the full scheduling, routing, retry, and observability stack without additional plumbing.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in running workflows on your own infrastructure, check out &lt;a href="https://www.pulumi.com/docs/deployments/deployments/customer-managed-agents/"&gt;customer-managed workflow runners&lt;/a&gt;. To see how Insights can help you understand and manage your cloud infrastructure, &lt;a href="https://www.pulumi.com/docs/insights/"&gt;get started with Pulumi Insights&lt;/a&gt;.&lt;/p&gt;</description><author>Levi Blackstone</author><author>Davide Massarenti</author><category>pulumi-cloud</category><category>features</category><category>engineering</category><category>insights</category></item><item><title>New in Pulumi IaC: `onError` Resource Hook</title><link>https://www.pulumi.com/blog/handling-deployment-errors/</link><pubDate>Mon, 23 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/handling-deployment-errors/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/handling-deployment-errors/index.png" /&gt;
&lt;p&gt;You can now control what happens when a resource fails during create, update, or delete—retry with backoff, fail fast, or handle errors in custom code. Last year, Pulumi IaC introduced the &lt;a href="https://www.pulumi.com/blog/resource-hooks/"&gt;resource hooks&lt;/a&gt; feature, allowing you to run custom code at different points in the lifecycle of resources. Today we&amp;rsquo;re adding the &lt;code&gt;onError&lt;/code&gt; hook so you can react when operations fail.&lt;/p&gt;
&lt;h2 id="recovering-from-errors"&gt;Recovering from errors&lt;/h2&gt;
&lt;p&gt;When a Pulumi program encounters an error while creating, updating, or deleting a resource, the operation halts and the error is reported back. Sometimes that&amp;rsquo;s not what we want—errors can be intermittent or temporary. If you&amp;rsquo;ve hit transient failures or resource-not-ready errors, the &lt;code&gt;onError&lt;/code&gt; hook can help.&lt;/p&gt;
&lt;p&gt;A common case is resource readiness: creating resources that depend on DNS propagation or the readiness of other servers. The program can fail simply because it ran too soon. Instead of failing, we can wait and retry. The example below shows how:&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="typescript,python,go,csharp" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/pulumi&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notStartedRetryHook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ErrorHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;retry-when-not-started&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;latestError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;latestError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;resource has not yet started&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// do not retry, this is another type of error
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// retry
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MyResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;res&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;hooks&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;onError&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;notStartedRetryHook&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retry_when_not_started&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorHookArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;latest_error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;resource has not yet started&amp;#34;&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;latest_error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt; &lt;span class="c1"&gt;# do not retry, this is another type of error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt; &lt;span class="c1"&gt;# retry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;not_started_retry_hook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;retry-when-not-started&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;retry_when_not_started&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;res&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResourceOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hooks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResourceHookBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;on_error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;not_started_retry_hook&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;strings&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;github.com/pulumi/pulumi/sdk/v3/go/pulumi&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RegisterErrorHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;retry-when-not-started&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ErrorHookArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;latest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;latest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;resource has not yet started&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// do not retry, this is another type of error&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// retry&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;NewMyResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;res&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;MyResourceArgs&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ResourceHooks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResourceHookBinding&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;OnError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ErrorHook&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Pulumi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ErrorHookStack&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Stack&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ErrorHookStack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;retryHook&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ErrorHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;retry-when-not-started&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;latestError&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;latestError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;resource has not yet started&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// do not retry, this is another type of error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// retry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MyResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;res&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MyResourceArgs&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CustomResourceOptions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Hooks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ResourceHookBinding&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;OnError&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;retryHook&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;Each time the operation fails, the hook receives the new error plus all previous attempts&amp;rsquo; errors (newest first). The hook returns true or false to tell Pulumi whether to retry. If you return false, the program fails as normal with the most recent error. With that information, you can implement many failure models:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use the number of errors to implement backoff—for example, wait one second on the first failure, two seconds on the second, and so on.&lt;/li&gt;
&lt;li&gt;For known-intermittent resources, always retry once before failing.&lt;/li&gt;
&lt;li&gt;Inspect error text to retry only for specific conditions (as in the example) and fail fast for others.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The callback runs in your language of choice, so you have full control over how failures are handled.&lt;/p&gt;
&lt;h2 id="next-steps"&gt;Next steps&lt;/h2&gt;
&lt;p&gt;This feature is fully supported in our Node, Python, Go, and .NET SDKs as of v3.219.0. For more information, see the &lt;a href="https://www.pulumi.com/docs/iac/concepts/resources/options/hooks/"&gt;hooks documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Java and YAML do not support resource hooks.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Thanks for reading, and feel free to reach out with any questions via &lt;a href="https://github.com/pulumi/pulumi"&gt;GitHub&lt;/a&gt;, &lt;a href="https://x.com/pulumicorp"&gt;X&lt;/a&gt;, or our &lt;a href="https://slack.pulumi.com/"&gt;Community Slack&lt;/a&gt;.&lt;/p&gt;</description><author>Tom Harding</author><category>features</category><category>infrastructure-as-code</category><category>releases</category></item><item><title>Introducing the Terraform State Provider for Pulumi ESC</title><link>https://www.pulumi.com/blog/esc-terraform-state-provider/</link><pubDate>Fri, 13 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/esc-terraform-state-provider/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/esc-terraform-state-provider/index.png" /&gt;
&lt;p&gt;Many organizations have years of infrastructure built and managed with Terraform.
Outputs such as VPC IDs, subnet lists, database endpoints, and cluster names are the connective tissue between infrastructure layers.
Getting those values into other tools and workflows often means manual copy-paste, wrapper scripts, or brittle glue code.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://www.pulumi.com/docs/esc/integrations/infrastructure/terraform/terraform-state/"&gt;&lt;code&gt;terraform-state&lt;/code&gt; provider&lt;/a&gt; for Pulumi ESC helps bridge that gap.
It reads outputs directly from your Terraform state files and makes them available as first-class values in your ESC environments — no scripts, no duplication, no drift.
Any output marked as &lt;code&gt;sensitive&lt;/code&gt; in your Terraform state is automatically treated as a secret in ESC.
If you&amp;rsquo;ve used &lt;a href="https://www.pulumi.com/docs/esc/integrations/infrastructure/pulumi-iac/pulumi-stacks/"&gt;&lt;code&gt;pulumi-stacks&lt;/code&gt;&lt;/a&gt; to read outputs from Pulumi stacks, this is the same idea for Terraform.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;terraform-state&lt;/code&gt; provider uses &lt;code&gt;fn::open::terraform-state&lt;/code&gt; to read from a Terraform state file and surface its outputs as ESC values.
Here&amp;rsquo;s an example that reads from an S3 backend, using the &lt;code&gt;aws-login&lt;/code&gt; provider for credentials, and exports a &lt;code&gt;KUBECONFIG&lt;/code&gt; for an EKS cluster managed by Terraform:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;terraform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::open::terraform-state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::open::aws-login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;oidc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;roleArn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;arn:aws:iam::123456789012:role/esc-oidc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;sessionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumi-environments-session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-terraform-state-bucket&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;path/to/terraform.tfstate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;us-west-2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${terraform.outputs.kubeconfig}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the environment is opened, &lt;code&gt;terraform.outputs&lt;/code&gt; contains every output from the Terraform state.
In this example we take the &lt;code&gt;kubeconfig&lt;/code&gt; output from a Terraform-managed EKS cluster and project it as a file,
so any tool that reads &lt;code&gt;KUBECONFIG&lt;/code&gt; - &lt;code&gt;kubectl&lt;/code&gt;, &lt;code&gt;helm&lt;/code&gt;, Pulumi - just works.
You can also reference outputs in &lt;code&gt;pulumiConfig&lt;/code&gt; to pass values like VPC IDs and subnet lists directly into Pulumi stacks.&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3 id="terraform-cloud-support"&gt;Terraform Cloud support&lt;/h3&gt;
&lt;p&gt;If your state lives in Terraform Cloud (or any compatible remote backend), the provider supports that too:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;terraform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::open::terraform-state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;organization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-terraform-org&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;workspace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-workspace&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;tfc-token-value&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pulumiConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${terraform.outputs.vpc_id}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;subnetIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${terraform.outputs.subnet_ids}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can point it at any Terraform Cloud-compatible backend by setting the optional &lt;code&gt;hostname&lt;/code&gt; property.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Check out the full &lt;a href="https://www.pulumi.com/docs/esc/integrations/infrastructure/terraform/terraform-state/"&gt;&lt;code&gt;terraform-state&lt;/code&gt; provider documentation&lt;/a&gt; for the complete reference.&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;You can also consume Terraform outputs directly in a Pulumi program with the &lt;a href="https://www.pulumi.com/registry/packages/terraform/"&gt;Pulumi Terraform provider&lt;/a&gt;.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>Claire Gaestel</author><category>esc</category><category>terraform</category><category>features</category></item><item><title>Schema Validation Comes to Pulumi ESC with fn::validate</title><link>https://www.pulumi.com/blog/esc-schema-validation-fn-validate/</link><pubDate>Thu, 12 Feb 2026 11:00:00 -0300</pubDate><guid>https://www.pulumi.com/blog/esc-schema-validation-fn-validate/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/esc-schema-validation-fn-validate/index.png" /&gt;
&lt;p&gt;Pulumi ESC environments can now validate configuration values against JSON Schema with the new &lt;code&gt;fn::validate&lt;/code&gt; built-in function. Invalid configurations are caught immediately when you save, preventing misconfigurations from reaching your deployments.&lt;/p&gt;
&lt;p&gt;Configuration errors are often discovered too late during deployment or, worse, in production. With &lt;code&gt;fn::validate&lt;/code&gt;, you define validation rules directly in your environment, and ESC enforces them at save time. If a value doesn&amp;rsquo;t match its schema, the environment cannot be saved until the issue is resolved.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;fn::validate&lt;/code&gt; function takes a JSON Schema and a value. If the value conforms to the schema, it passes through unchanged. If not, ESC raises a validation error.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::validate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type: number, minimum: 1, maximum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;65535&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This validates that &lt;code&gt;port&lt;/code&gt; is a number between 1 and 65535. The evaluated result is simply &lt;code&gt;8080&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="validating-objects-with-required-fields"&gt;Validating objects with required fields&lt;/h2&gt;
&lt;p&gt;For complex configurations, you can enforce structure and required fields:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::validate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;string }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;number }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;string }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;host, port, name]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;db.example.com&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5432&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;myapp&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If any required field is missing or has the wrong type, the environment cannot be saved.&lt;/p&gt;
&lt;h2 id="reusing-schemas-across-environments"&gt;Reusing schemas across environments&lt;/h2&gt;
&lt;p&gt;Define schemas once and reference them across multiple environments. Using the &lt;a href="https://www.pulumi.com/docs/esc/environments/syntax/builtin-properties/environments/"&gt;&lt;code&gt;environments&lt;/code&gt; built-in property&lt;/a&gt; keeps the schema out of your environment&amp;rsquo;s output:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Schema environment (my-project/schemas)&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;database-schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;string }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;number }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;host, port]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Environment using the schema&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::validate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${environments.my-project.schemas.database-schema}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;prod-db.example.com&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5432&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This pattern ensures consistent validation rules across teams and projects.&lt;/p&gt;
&lt;h2 id="what-happens-when-validation-fails"&gt;What happens when validation fails&lt;/h2&gt;
&lt;p&gt;When a value doesn&amp;rsquo;t conform to its schema, ESC returns a clear error message:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::validate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;string }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This raises: &lt;code&gt;expected string, got number&lt;/code&gt;. The environment cannot be saved until you fix the value or update the schema.&lt;/p&gt;
&lt;h2 id="when-to-use-schema-validation"&gt;When to use schema validation&lt;/h2&gt;
&lt;p&gt;Enable &lt;code&gt;fn::validate&lt;/code&gt; for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Values with specific type requirements (numbers, strings, arrays)&lt;/li&gt;
&lt;li&gt;Objects that must have certain fields present&lt;/li&gt;
&lt;li&gt;Numbers that must fall within a valid range&lt;/li&gt;
&lt;li&gt;Configurations shared across multiple environments&lt;/li&gt;
&lt;li&gt;Any value where catching errors early prevents downstream issues&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;fn::validate&lt;/code&gt; function is available now in all Pulumi ESC environments. Add schema validation to your existing environments or use it when creating new ones.&lt;/p&gt;
&lt;p&gt;For more information, see the &lt;a href="https://www.pulumi.com/docs/esc/environments/syntax/builtin-functions/fn-validate/"&gt;fn::validate documentation&lt;/a&gt;.&lt;/p&gt;</description><author>Pablo Terradillos</author><author>Claire Gaestel</author><category>esc</category><category>features</category></item><item><title>Registry usage insights: know which stacks run which versions</title><link>https://www.pulumi.com/blog/registry-usage-insights/</link><pubDate>Thu, 12 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/registry-usage-insights/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/registry-usage-insights/index.png" /&gt;
&lt;p&gt;Platform teams need visibility into package adoption at scale. Responding to security advisories, planning deprecations, and tracking version sprawl all require knowing which stacks run which package versions across your organization.&lt;/p&gt;
&lt;h2 id="from-individual-to-organizational-visibility"&gt;From Individual to Organizational Visibility&lt;/h2&gt;
&lt;p&gt;Previously, we &lt;a href="https://www.pulumi.com/blog/announcing-pulumi-private-registry/"&gt;introduced the &amp;ldquo;Used by&amp;rdquo; tab&lt;/a&gt; on individual package pages, giving you visibility into which stacks use a specific package. However, navigating package by package doesn&amp;rsquo;t scale when you&amp;rsquo;re managing dozens of packages across hundreds of stacks.&lt;/p&gt;
&lt;p&gt;Today, we&amp;rsquo;re extending that visibility to the organization level. You can now see adoption data for all packages at a glance, filter by usage status, and share specific views with your team.&lt;/p&gt;
&lt;h2 id="what-you-can-see"&gt;What You Can See&lt;/h2&gt;
&lt;p&gt;&lt;img src="usage-columns.png" alt="Package list showing usage columns"&gt;&lt;/p&gt;
&lt;p&gt;The package list now displays three usage columns for each package:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Stacks on latest&lt;/strong&gt;: the number of stacks running the latest version&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not on latest&lt;/strong&gt;: the number of stacks running older versions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Total&lt;/strong&gt;: all stacks using any version of the package&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These numbers update as stacks are deployed, giving you a real-time view of adoption across your organization.&lt;/p&gt;
&lt;h2 id="find-what-matters-with-filters"&gt;Find What Matters with Filters&lt;/h2&gt;
&lt;p&gt;&lt;img src="filter-dropdown.png" alt="Filter dropdown"&gt;&lt;/p&gt;
&lt;p&gt;Three filters help you find packages that need attention:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Used&lt;/strong&gt;: packages with at least one stack&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unused&lt;/strong&gt;: packages with zero usage&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not on latest&lt;/strong&gt;: packages where stacks are running older versions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Combine filters with search to find specific packages.&lt;/p&gt;
&lt;h2 id="browse-all-packages-in-one-place"&gt;Browse All Packages in One Place&lt;/h2&gt;
&lt;p&gt;&lt;img src="registry-tab.png" alt="Registry tab"&gt;&lt;/p&gt;
&lt;p&gt;The new &lt;strong&gt;Registry&lt;/strong&gt; tab under Platform shows all packages available to your organization, including public providers and components from &lt;a href="https://www.pulumi.com/registry/"&gt;pulumi.com/registry&lt;/a&gt; alongside your organization&amp;rsquo;s private packages. The &lt;strong&gt;Private Components&lt;/strong&gt; tab (previously called Components) now includes the same usage columns and filters.&lt;/p&gt;
&lt;h2 id="share-specific-views"&gt;Share Specific Views&lt;/h2&gt;
&lt;p&gt;Search queries, filters, and pagination sync to the URL. Copy the URL to share a specific view with your team, or bookmark it for quick access to your regular monitoring workflow.&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why This Matters&lt;/h2&gt;
&lt;p&gt;These features are designed for the scenarios platform teams face regularly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Security response&lt;/strong&gt;: filter to &amp;ldquo;Not on latest&amp;rdquo; to identify stacks running vulnerable versions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deprecation planning&lt;/strong&gt;: before retiring a package, check its usage to understand the migration scope&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Version sprawl&lt;/strong&gt;: identify packages where teams are running many different versions and prioritize standardization efforts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adoption tracking&lt;/strong&gt;: see which packages are gaining traction and which aren&amp;rsquo;t being adopted&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="get-started"&gt;Get Started&lt;/h2&gt;
&lt;p&gt;Navigate to &lt;strong&gt;Platform &amp;gt; Registry&lt;/strong&gt; in Pulumi Cloud to explore your organization&amp;rsquo;s packages with the new usage columns and filters. For more details on the private registry features, see the &lt;a href="https://www.pulumi.com/docs/idp/concepts/private-registry/"&gt;Private Registry documentation&lt;/a&gt;.&lt;/p&gt;</description><author>Pulumi IDP Team</author><category>internal-developer-platform</category><category>features</category><category>platform-engineering</category><category>pulumi-cloud</category></item><item><title>Introducing envVarMappings for Provider Credentials</title><link>https://www.pulumi.com/blog/new-provider-resource-option-environment-variable-remapping/</link><pubDate>Thu, 12 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/new-provider-resource-option-environment-variable-remapping/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/new-provider-resource-option-environment-variable-remapping/index.png" /&gt;
&lt;p&gt;Running multiple providers with different credentials in the same Pulumi program has always been tricky.
Providers expect fixed environment variable names like &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; or &lt;code&gt;ARM_CLIENT_SECRET&lt;/code&gt;, so if you need two AWS providers targeting different accounts, you couldn&amp;rsquo;t configure them both via environment variables.&lt;/p&gt;
&lt;p&gt;Pulumi v3.220.0 introduces &lt;code&gt;envVarMappings&lt;/code&gt;, a new resource option that solves this problem by letting you remap provider environment variables to custom keys.&lt;/p&gt;
&lt;p&gt;When configuring a Pulumi provider to authenticate against a cloud provider, there are two main options available.
You can set authentication values as secrets in your Pulumi.yaml config:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi config &lt;span class="nb"&gt;set&lt;/span&gt; azure-native:clientSecret &amp;lt;clientSecret&amp;gt; --secret
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternately, you can also use the terminal environment of where you&amp;rsquo;re running your Pulumi commands:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;ARM_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1234567&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using environment variables in this manner is especially useful in CI environments, or when you&amp;rsquo;d rather not write that auth token to state, even encrypted.
But there&amp;rsquo;s currently several use cases where this breaks down, due to the hard-coded nature of the environment variables that a given provider expects.&lt;/p&gt;
&lt;h2 id="multiple-providers-or-provider-instances-that-expect-different-authentication-values-but-have-the-same-variable-key"&gt;Multiple providers or provider instances that expect different authentication values but have the same variable key&lt;/h2&gt;
&lt;p&gt;For example, if you are using multiple explicit providers targeting different Azure accounts, you were not able to set these separate configurations via environment variable.&lt;/p&gt;
&lt;p&gt;Instead, users would have to set these values in the provider config, which may not be desirable for all use cases.
Not only does the provider config write secrets to state (albeit of course encrypted), but it can also result in a noisy diff on an otherwise no-op upgrade when token rotation is used.&lt;/p&gt;
&lt;h2 id="remapping-environment-variables"&gt;Remapping environment variables&lt;/h2&gt;
&lt;p&gt;For this and similar scenarios, we have a new solution for you: setting mappings of environment variable keys on your provider.
The concept is as follows:&lt;/p&gt;
&lt;p&gt;&amp;ldquo;For any environment variable that my Pulumi provider expects, I want to be able to tell the provider to use the value of a custom-defined environment variable instead.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="example"&gt;Example&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say your provider expects &lt;code&gt;ARM_CLIENT_SECRET&lt;/code&gt;, but you want it to use a different value than the one set in your shell. First, define a custom environment variable with your desired value:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;CUSTOM_ARM_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;7654321&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, use &lt;code&gt;envVarMappings&lt;/code&gt; to tell the provider: &amp;ldquo;When you look for &lt;code&gt;ARM_CLIENT_SECRET&lt;/code&gt;, read from &lt;code&gt;CUSTOM_ARM_CLIENT_SECRET&lt;/code&gt; instead.&amp;rdquo; The mapping format is &lt;code&gt;{ &amp;quot;SOURCE_VAR&amp;quot;: &amp;quot;TARGET_VAR&amp;quot; }&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="typescript,python,go,csharp,java,yaml" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;command-provider&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;envVarMappings&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// If CUSTOM_ARM_CLIENT_SECRET exists, provider sees the value of ARM_CLIENT_SECRET
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;CUSTOM_ARM_CLIENT_SECRET&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ARM_CLIENT_SECRET&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;command-provider&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResourceOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;env_var_mappings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# If CUSTOM_ARM_CLIENT_SECRET exists, provider sees the value of ARM_CLIENT_SECRET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;CUSTOM_ARM_CLIENT_SECRET&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ARM_CLIENT_SECRET&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;command-provider&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ProviderArgs&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnvVarMappings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// If CUSTOM_ARM_CLIENT_SECRET exists, provider sees the value of ARM_CLIENT_SECRET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;CUSTOM_ARM_CLIENT_SECRET&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ARM_CLIENT_SECRET&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;command-provider&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProviderArgs&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CustomResourceOptions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;EnvVarMappings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// If CUSTOM_ARM_CLIENT_SECRET exists, provider sees the value of ARM_CLIENT_SECRET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;CUSTOM_ARM_CLIENT_SECRET&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;ARM_CLIENT_SECRET&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="java" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;command-provider&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProviderArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomResourceOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;envVarMappings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// If CUSTOM_ARM_CLIENT_SECRET exists, provider sees the value of ARM_CLIENT_SECRET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;CUSTOM_ARM_CLIENT_SECRET&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ARM_CLIENT_SECRET&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="yaml" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command-provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumi:providers:command&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;envVarMappings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# If CUSTOM_ARM_CLIENT_SECRET exists, provider sees the value of ARM_CLIENT_SECRET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;CUSTOM_ARM_CLIENT_SECRET&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ARM_CLIENT_SECRET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;You can now customize each environment variable value your provider sees by defining a new environment variable, and then mapping your provider&amp;rsquo;s defined variable to yours.
Try it out with Pulumi v3.220.0 today!&lt;/p&gt;
&lt;p&gt;For full details, see the &lt;a href="https://www.pulumi.com/docs/iac/concepts/resources/options/envvarmappings/"&gt;envVarMappings documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;</description><author>Guinevere Saenger</author><category>features</category><category>packages</category></item><item><title>Pulumi Neo Now Supports AGENTS.md</title><link>https://www.pulumi.com/blog/pulumi-neo-now-supports-agentsmd/</link><pubDate>Fri, 06 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-neo-now-supports-agentsmd/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-neo-now-supports-agentsmd/index.png" /&gt;
&lt;p&gt;Neo now reads &lt;a href="https://agents.md/"&gt;AGENTS.md&lt;/a&gt; files, the open standard for giving AI coding tools context about your project. If you&amp;rsquo;re already using AGENTS.md, Neo will pick up those same instructions automatically.&lt;/p&gt;
&lt;h2 id="the-problem-agentsmd-solves"&gt;The problem AGENTS.md solves&lt;/h2&gt;
&lt;p&gt;Every codebase has conventions that aren&amp;rsquo;t captured in linters or formatters. Maybe your team uses a specific naming pattern for infrastructure resources. Maybe there&amp;rsquo;s a particular way you structure tests, or commands that need to run in a certain order. These are the things you&amp;rsquo;d explain to a new team member, and now you can explain them to AI tools too.&lt;/p&gt;
&lt;p&gt;Without something like AGENTS.md, you end up repeating yourself. Every conversation starts with &amp;ldquo;remember to use TypeScript&amp;rdquo; or &amp;ldquo;make sure you add the environment tag.&amp;rdquo; It&amp;rsquo;s tedious, and things slip through.&lt;/p&gt;
&lt;p&gt;AGENTS.md gives these instructions a home. You write them once, commit the file to your repo, and any tool that supports the format picks them up automatically.&lt;/p&gt;
&lt;h2 id="what-to-put-in-yours"&gt;What to put in yours&lt;/h2&gt;
&lt;p&gt;Think about what you&amp;rsquo;d tell someone on their first day working in the codebase. How do you run tests? Are there naming conventions? Any gotchas they should know about?&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example for a Pulumi project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Infrastructure conventions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Run tests with &lt;span class="sb"&gt;`make test`&lt;/span&gt;. This spins up LocalStack, so Docker must be running.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Stacks are named &lt;span class="sb"&gt;`{service}-{region}-{env}`&lt;/span&gt; (e.g., &lt;span class="sb"&gt;`payments-us-west-2-prod`&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Only the platform team deploys to prod stacks.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;All resources need these tags: &lt;span class="sb"&gt;`cost-center`&lt;/span&gt;, &lt;span class="sb"&gt;`team`&lt;/span&gt;, &lt;span class="sb"&gt;`environment`&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Reusable components live in &lt;span class="sb"&gt;`components/`&lt;/span&gt;. Check there before writing
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;something new.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s no required structure, just markdown. Some teams write a few lines, others write detailed guides. Start small and add things as you notice yourself repeating instructions.&lt;/p&gt;
&lt;h2 id="how-neo-handles-agentsmd"&gt;How Neo handles AGENTS.md&lt;/h2&gt;
&lt;p&gt;When you point Neo at a repository, it reads any AGENTS.md file it finds and applies those instructions to its work. You don&amp;rsquo;t need to mention the file or remind Neo about your conventions.&lt;/p&gt;
&lt;p&gt;If you have a monorepo, you can put AGENTS.md files in subdirectories too. Neo uses the nearest one to wherever it&amp;rsquo;s working, so you can have general instructions at the root and more specific ones in subpackages.&lt;/p&gt;
&lt;p&gt;Your instructions in conversation always take precedence, so you can override the file when you need to. If you&amp;rsquo;ve also set up &lt;a href="https://www.pulumi.com/docs/ai/settings/#custom-instructions"&gt;Custom Instructions&lt;/a&gt; at the organization level, Neo applies those first, then AGENTS.md on top.&lt;/p&gt;
&lt;h2 id="works-with-the-tools-youre-already-using"&gt;Works with the tools you&amp;rsquo;re already using&lt;/h2&gt;
&lt;p&gt;AGENTS.md is an open format supported by most AI coding tools: Cursor, Windsurf, GitHub Copilot, Zed, and now Neo. If your team uses different tools for different tasks, they&amp;rsquo;ll all follow the same project conventions without any extra configuration.&lt;/p&gt;
&lt;p&gt;The format is managed by the Agentic AI Foundation under the Linux Foundation, and it&amp;rsquo;s already in use in over 60,000 open source projects. See &lt;a href="https://agents.md/"&gt;agents.md&lt;/a&gt; for the full specification.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Add an AGENTS.md file to your repository and Neo will start using it on your next task. For more on configuring Neo, including organization-wide Custom Instructions and Slash Commands, see the &lt;a href="https://www.pulumi.com/docs/ai/settings/"&gt;Settings documentation&lt;/a&gt;.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>pulumi-neo</category><category>ai</category><category>features</category></item><item><title>Announcing OpenAPI support for the Pulumi Cloud REST API</title><link>https://www.pulumi.com/blog/announcing-openapi-support-pulumi-cloud/</link><pubDate>Thu, 05 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/announcing-openapi-support-pulumi-cloud/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/announcing-openapi-support-pulumi-cloud/index.png" /&gt;
&lt;p&gt;We&amp;rsquo;re thrilled to announce that the Pulumi Cloud REST API is now described by an OpenAPI 3.0 specification, and we&amp;rsquo;re just getting started.&lt;/p&gt;
&lt;p&gt;This is a feature that has been a long time coming. We have heard your requests for OpenAPI support &lt;a href="https://github.com/pulumi/pulumi-cloud-requests/issues/100"&gt;loud and clear&lt;/a&gt;, and we&amp;rsquo;re excited to share that not only do we have a published specification for consumption, but our API code is now built from this specification as well. Moving forward, this single source of truth unlocks better tooling, tighter integration, and a more predictable API experience for everyone.&lt;/p&gt;
&lt;p&gt;You can fetch the spec directly from the API at runtime or use it for client generation, validation, and documentation, all from one machine-readable contract.&lt;/p&gt;
&lt;h2 id="a-single-contract-for-the-pulumi-cloud-rest-api"&gt;A single contract for the Pulumi Cloud REST API&lt;/h2&gt;
&lt;p&gt;The Pulumi Cloud API powers the Pulumi CLI, the Pulumi Console, and third-party integrations. Until now, there was no single, published machine-readable description of that API. We&amp;rsquo;ve changed that. The API is now defined and served as a standard OpenAPI 3.0.3 document.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Runtime discovery&lt;/strong&gt;: You can retrieve the spec from the API itself, so your tooling always sees the same surface the service implements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client generation&lt;/strong&gt;: Use your favorite OpenAPI tooling (e.g. OpenAPI Generator, Swagger Codegen) to generate API clients in the language of your choice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation and testing&lt;/strong&gt;: Validate requests and responses, or build mocks and tests, from the same spec the service uses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation&lt;/strong&gt;: The spec is the source of truth, not a separate, hand-maintained API doc that can drift from reality. Load the spec into Swagger UI, Redoc, or another viewer to browse the Pulumi Cloud API interactively.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-get-the-spec"&gt;How to get the spec&lt;/h2&gt;
&lt;p&gt;Send a GET request to:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;https://api.pulumi.com/api/openapi/pulumi-spec.json
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;No authentication is required. The response is the OpenAPI 3.0 document for the Pulumi Cloud API, describing the supported, documented API surface.&lt;/p&gt;
&lt;h2 id="source-of-truth-and-stability"&gt;Source of truth and stability&lt;/h2&gt;
&lt;p&gt;We do not hand-write the OpenAPI spec. We generate it from the same API definition that drives our backend and console code. When we add or change API routes or models, we regenerate the spec so the published document stays in sync with what the service actually implements. That gives you a clear, stable contract for the Pulumi Cloud API.&lt;/p&gt;
&lt;h2 id="what-we-are-building-next"&gt;What we are building next&lt;/h2&gt;
&lt;p&gt;We are using this spec as the foundation for our own tooling, and have plans to continue leveraging the spec in our toolchain long-term.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CLI&lt;/strong&gt;: We plan to drive the Pulumi CLI’s API client from the OpenAPI spec so that CLI and API stay in lockstep.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pulumi Service Provider&lt;/strong&gt;: We are also building towards day 1 updates to the &lt;a href="https://www.pulumi.com/registry/packages/pulumiservice/"&gt;Pulumi Service Provider&lt;/a&gt; so that new and changed API resources are generated from the spec and ship in sync with the service.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docs Enhancements&lt;/strong&gt;: Although you can load the spec using Swagger UI for your own browsing, we are intent on shipping enhancements to our &lt;a href="https://www.pulumi.com/docs/reference/cloud-rest-api/"&gt;public REST API docs&lt;/a&gt; that will keep them up-to-date according to the OpenAPI spec.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As we ship those updates, you will get a single source of truth from API to CLI to provider.&lt;/p&gt;
&lt;p&gt;If you have questions or feedback about the OpenAPI spec or the Pulumi Cloud API, reach out in our &lt;a href="https://slack.pulumi.com/"&gt;Community Slack&lt;/a&gt; or open an issue in the &lt;a href="https://github.com/pulumi/pulumi"&gt;Pulumi repository&lt;/a&gt;. We&amp;rsquo;re excited to see what you build with it.&lt;/p&gt;</description><author>Davide Massarenti</author><author>Claire Gaestel</author><author>Devon Grove</author><author>Arun Loganathan</author><author>Zac Cook</author><category>features</category><category>pulumi-cloud</category><category>api</category></item><item><title>Neo: Share Tasks for Collaborative AI Infrastructure Operations</title><link>https://www.pulumi.com/blog/neo-task-sharing/</link><pubDate>Wed, 04 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/neo-task-sharing/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-task-sharing/index.png" /&gt;
&lt;p&gt;Neo shows its work, but until now that context was only viewable by the user that initiated the conversation. When you wanted a teammate&amp;rsquo;s input on a decision Neo made, you had to describe it in Slack or screenshot fragments of the conversation. Today we&amp;rsquo;re introducing task sharing: share a read-only view of any Neo task with anyone in your organization, full context preserved.&lt;/p&gt;
&lt;p&gt;To share a Neo task, click the share button to generate a read-only link, then send it to a teammate. They see the complete picture: the original prompt, Neo&amp;rsquo;s reasoning process, the actions it took, and the outcome. Instead of writing up what happened and losing detail in the retelling, you share the task itself.&lt;/p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Sharing a Neo task"
autoplay muted playsinline
loop &gt;
&lt;source src="neo-task-share.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;p&gt;We built this with security as a core constraint. The original task system enforced strict RBAC, ensuring users could only see and act on resources they had permission to access. Task sharing preserves these guarantees. Viewers can see the conversation with Neo, but they cannot trigger any actions, and links within the shared task to stacks or resources still enforce the viewer&amp;rsquo;s existing permissions.&lt;/p&gt;
&lt;p&gt;The feature is available now. The next time you want a second opinion or need to show a colleague how you solved something, share the task. You&amp;rsquo;re no longer working alone.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>pulumi-neo</category><category>ai</category><category>features</category></item><item><title>Pulumi Agent Skills: Best practices and more for AI coding assistants</title><link>https://www.pulumi.com/blog/pulumi-agent-skills/</link><pubDate>Thu, 29 Jan 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-agent-skills/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-agent-skills/index.png" /&gt;
&lt;p&gt;AI coding assistants have transformed how developers write software, including infrastructure code. Tools like Claude Code, Cursor, and GitHub Copilot can generate code, explain complex systems, and automate tedious tasks. But when it comes to infrastructure, these tools often produce code that works but misses the mark on patterns that matter: proper secret handling, correct resource dependencies, idiomatic component structure, and the dozens of other details that separate working infrastructure from production-ready infrastructure.&lt;/p&gt;
&lt;p&gt;We built &lt;a href="https://www.pulumi.com/product/neo/"&gt;Neo&lt;/a&gt; for teams that want deep Pulumi expertise combined with organizational context and deployment governance. But developers have preferred tools, and we want people to succeed with Pulumi wherever they work. Some teams live in Claude Code. Others use Cursor, Copilot, Codex, Gemini CLI, or other platforms. That is why we are releasing Pulumi Agent Skills, a collection of packaged expertise that teaches any AI coding assistant how to work with Pulumi the way an experienced practitioner would.&lt;/p&gt;
&lt;h2 id="what-are-agent-skills"&gt;What are agent skills?&lt;/h2&gt;
&lt;p&gt;Skills are structured knowledge packages that follow the open &lt;a href="https://agentskills.io"&gt;Agent Skills&lt;/a&gt; specification. They work across multiple AI coding platforms including Claude Code, GitHub Copilot, Cursor, VS Code, Codex, and Gemini CLI. When you install Pulumi skills, your AI assistant gains access to detailed workflows, code patterns, and decision trees for common infrastructure tasks.&lt;/p&gt;
&lt;h2 id="available-pulumi-skills"&gt;Available Pulumi skills&lt;/h2&gt;
&lt;p&gt;We are launching a set of skills organized into two plugin groups: authoring and migration. You can install all skills at once or choose specific plugin groups based on your needs.&lt;/p&gt;
&lt;h3 id="authoring-skills"&gt;Authoring skills&lt;/h3&gt;
&lt;p&gt;This plugin includes four skills focused on code quality, reusability, and configuration.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pulumi best practices&lt;/strong&gt; encodes the patterns that prevent common mistakes. It covers output handling, component structure, secrets management, safe refactoring with aliases, and deployment workflows. The skill flags anti-patterns that can cause issues with preview, dependencies, and production deployments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pulumi Component&lt;/strong&gt; provides a complete guide for authoring ComponentResource classes. The skill covers designing component interfaces, multi-language support, and distribution. It teaches assistants how to build reusable infrastructure abstractions that work across TypeScript, Python, Go, C#, Java, and YAML.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pulumi Automation API&lt;/strong&gt; covers programmatic orchestration of Pulumi operations. The skill explains when to use Automation API versus the CLI, the tradeoffs between local source and inline programs, and patterns for multi-stack deployments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pulumi ESC&lt;/strong&gt; covers centralized secrets and configuration management. The skill guides assistants through setting up dynamic OIDC credentials, composing environments, and integrating secrets into Pulumi programs and other applications.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="migration-skills"&gt;Migration skills&lt;/h3&gt;
&lt;p&gt;Convert and import infrastructure from other tools to Pulumi. This plugin includes four skills covering complete migration workflows, not just syntax translation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Terraform to Pulumi&lt;/strong&gt; walks through the full migration workflow. It handles state translation, provider version alignment, and the iterative process of achieving a clean &lt;code&gt;pulumi preview&lt;/code&gt; with no unexpected changes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CloudFormation to Pulumi&lt;/strong&gt; covers the complete AWS CloudFormation migration workflow, from template conversion and stack import to handling CloudFormation-specific constructs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CDK to Pulumi&lt;/strong&gt; covers the complete AWS CDK migration workflow end to end, from conversion and import to handling CDK-specific constructs like Lambda-backed custom resources and cross-stack references.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Azure to Pulumi&lt;/strong&gt; covers the complete Azure Resource Manager and Bicep migration workflow, handling template conversion and resource import with guidance on achieving zero-diff validation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-install"&gt;How to install&lt;/h2&gt;
&lt;h3 id="claude-code-plugin-marketplace"&gt;Claude Code plugin marketplace&lt;/h3&gt;
&lt;p&gt;For Claude Code users, the plugin system provides the simplest installation experience:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;claude plugin marketplace add pulumi/agent-skills
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;claude plugin install pulumi-authoring &lt;span class="c1"&gt;# Install authoring skills&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;claude plugin install pulumi-migration &lt;span class="c1"&gt;# Install migration skills&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can install both plugin groups or choose only the ones you need.&lt;/p&gt;
&lt;h3 id="universal-installation"&gt;Universal installation&lt;/h3&gt;
&lt;p&gt;For Cursor, GitHub Copilot, VS Code, Codex, Gemini and other platforms, use the universal &lt;a href="https://agentskills.io"&gt;Agent Skills&lt;/a&gt; CLI:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx skills add pulumi/agent-skills --skill &lt;span class="s1"&gt;&amp;#39;*&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works across all platforms that support the Agent Skills specification.&lt;/p&gt;
&lt;h2 id="using-skills"&gt;Using skills&lt;/h2&gt;
&lt;p&gt;Once installed, skills activate automatically based on context. When you ask your assistant to help migrate a Terraform project, it draws on the Terraform skill&amp;rsquo;s workflow. When you are debugging why resources are being recreated unexpectedly, the best practices skill helps the assistant check for missing aliases.&lt;/p&gt;
&lt;p&gt;In Codex and Claude Code, you can invoke skills directly via slash commands.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/pulumi-terraform-to-pulumi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or describe what you need in natural language:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Help me migrate this CDK application to Pulumi&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Review this Pulumi code for best practices issues&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Create a reusable component for a web service with load balancer&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The assistant will follow the skill&amp;rsquo;s procedures, ask clarifying questions when needed, and produce output that reflects Pulumi best practices rather than generic code generation.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;We expect this collection to grow. If you have Pulumi expertise worth packaging, whether provider-specific patterns, debugging workflows, or operational practices, we welcome contributions. See the &lt;a href="https://github.com/pulumi/agent-skills/blob/main/CONTRIBUTING.md"&gt;contributing guide&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;The skills are available now in the &lt;a href="https://github.com/pulumi/agent-skills"&gt;agent-skills repository&lt;/a&gt;. Install them in your preferred AI coding environment and let us know what you build.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>ai</category><category>platform-engineering</category><category>features</category><category>claude-code</category><category>codex</category><category>ai-agents</category></item><item><title>Manage Cloud Visibility and Governance with Infrastructure as Code</title><link>https://www.pulumi.com/blog/pulumi-service-provider-insights-resources/</link><pubDate>Mon, 26 Jan 2026 09:00:00 -0800</pubDate><guid>https://www.pulumi.com/blog/pulumi-service-provider-insights-resources/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-service-provider-insights-resources/index.png" /&gt;
&lt;p&gt;Do you know what cloud resources are running in your environment right now? Many organizations struggle to maintain visibility across their cloud estate, especially for resources created outside of infrastructure as code. Without complete visibility, you can&amp;rsquo;t enforce compliance, optimize costs, or identify security risks.&lt;/p&gt;
&lt;p&gt;Today, we&amp;rsquo;re excited to announce new resources in the &lt;a href="https://www.pulumi.com/registry/packages/pulumiservice/"&gt;Pulumi Service Provider&lt;/a&gt; that solve this problem by enabling you to discover all cloud resources and enforce governance policies programmatically using infrastructure as code.&lt;/p&gt;
&lt;p&gt;With these new resources, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Discover all cloud resources&lt;/strong&gt; across AWS, Azure, GCP, Kubernetes, or OCI environments, including resources not managed by Pulumi&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Import discovered resources&lt;/strong&gt; into Pulumi management using &lt;a href="https://www.pulumi.com/docs/insights/discovery/visual-import/"&gt;Visual Import&lt;/a&gt; to bring unmanaged infrastructure under IaC control&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enforce compliance at scale&lt;/strong&gt; by organizing resources into Policy Groups and applying policy packs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automate governance workflows&lt;/strong&gt; by managing everything through code, enabling GitOps and CI/CD integration&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="whats-new"&gt;What&amp;rsquo;s New&lt;/h2&gt;
&lt;p&gt;The Pulumi Service Provider now includes three new resources for managing cloud visibility and governance:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;InsightsAccount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Configures cloud provider scanning for resource discovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PolicyGroup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Organizes stacks or cloud accounts for policy enforcement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getPolicyPacks&lt;/code&gt; / &lt;code&gt;getPolicyPack&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Data sources for querying available policy packs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Let&amp;rsquo;s explore each of these in detail.&lt;/p&gt;
&lt;h2 id="insights-accounts-discover-your-cloud-resources"&gt;Insights Accounts: Discover Your Cloud Resources&lt;/h2&gt;
&lt;p&gt;An &lt;code&gt;InsightsAccount&lt;/code&gt; connects Pulumi Cloud to your cloud provider, enabling automated scanning and discovery of all resources in your environment. This gives you complete visibility into your cloud estate, including resources that aren&amp;rsquo;t managed by Pulumi.&lt;/p&gt;
&lt;h3 id="key-features"&gt;Key Features&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi-cloud support&lt;/strong&gt;: Scan AWS, Azure, GCP, Kubernetes, and OCI environments&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scheduled scanning&lt;/strong&gt;: Configure daily automated scans or trigger them on-demand&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource tagging&lt;/strong&gt;: Organize your accounts with custom tags&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="example-creating-an-aws-insights-account"&gt;Example: Creating an AWS Insights Account&lt;/h3&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="yaml,typescript,python,go" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="yaml" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;insights-example&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# ESC environment with AWS credentials&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;aws-credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumiservice:Environment&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;organization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-org&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;insights&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-credentials&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;yaml&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::stringAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; values:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; aws:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; login:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; fn::open::aws-login:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; oidc:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; roleArn: arn:aws:iam::123456789012:role/PulumiInsightsRole
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; sessionName: pulumi-insights
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; environmentVariables:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; AWS_REGION: us-west-2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Insights account for AWS scanning&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;aws-insights&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumiservice:InsightsAccount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;organizationName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-org&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;accountName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;production-aws&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;insights/aws-credentials&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;scanSchedule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;daily&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;providerConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;regions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;us-west-2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;us-east-1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;production&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;team&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;platform&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/pulumi&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumiservice&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/pulumiservice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ESC environment with AWS credentials
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;awsCredentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;aws-credentials&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;organization&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;my-org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;insights&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws-credentials&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;yaml&lt;/span&gt;: &lt;span class="kt"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StringAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;values:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; aws:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; login:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; fn::open::aws-login:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; oidc:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; roleArn: arn:aws:iam::123456789012:role/PulumiInsightsRole
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; sessionName: pulumi-insights
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; environmentVariables:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; AWS_REGION: us-west-2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Insights account for AWS scanning
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;awsInsights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InsightsAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;aws-insights&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;organizationName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;my-org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;accountName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;production-aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;: &lt;span class="kt"&gt;pulumi.interpolate&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;awsCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;awsCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;scanSchedule&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;daily&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;providerConfig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;regions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-east-1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;production&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;team&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_pulumiservice&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;pulumiservice&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ESC environment with AWS credentials&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;aws_credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pulumiservice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;aws-credentials&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;organization&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;my-org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;insights&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;aws-credentials&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;values:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; aws:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; login:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; fn::open::aws-login:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; oidc:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; roleArn: arn:aws:iam::123456789012:role/PulumiInsightsRole
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; sessionName: pulumi-insights
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; environmentVariables:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; AWS_REGION: us-west-2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Insights account for AWS scanning&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;aws_insights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pulumiservice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InsightsAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;aws-insights&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;organization_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;my-org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;account_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;production-aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aws_credentials&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aws_credentials&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;scan_schedule&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;daily&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;provider_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;regions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-east-1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;environment&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;production&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;team&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;github.com/pulumi/pulumi-pulumiservice/sdk/go/pulumiservice&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;github.com/pulumi/pulumi/sdk/v3/go/pulumi&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ESC environment with AWS credentials&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;awsCredentials&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewEnvironment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;aws-credentials&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnvironmentArgs&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Organization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;my-org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;insights&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;aws-credentials&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Yaml&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewStringAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;values:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; aws:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; login:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; fn::open::aws-login:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; oidc:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; roleArn: arn:aws:iam::123456789012:role/PulumiInsightsRole
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; sessionName: pulumi-insights
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; environmentVariables:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; AWS_REGION: us-west-2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Insights account for AWS scanning&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewInsightsAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;aws-insights&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InsightsAccountArgs&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;OrganizationName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;my-org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;AccountName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;production-aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%s/%s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;awsCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;awsCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ScanSchedule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;daily&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ProviderConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;regions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToStringArray&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;us-east-1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StringMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;environment&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;production&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;team&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h2 id="policy-groups-enforce-compliance-at-scale"&gt;Policy Groups: Enforce Compliance at Scale&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;PolicyGroup&lt;/code&gt; lets you organize resources and apply policy packs for compliance enforcement. Policy Groups support two entity types: Stacks and Accounts.&lt;/p&gt;
&lt;p&gt;You can configure policy groups in two modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Audit mode&lt;/strong&gt;: Reports policy violations without blocking operations. This supports both Stacks and Accounts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Preventative mode&lt;/strong&gt;: Blocks operations that violate policies. This mode is only available for Stacks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="example-stack-based-policy-group"&gt;Example: Stack-Based Policy Group&lt;/h3&gt;
&lt;p&gt;Apply compliance policies to your Pulumi stacks:&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="yaml,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="yaml" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;policy-group-example&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;production-policies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumiservice:PolicyGroup&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;production-compliance&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;organizationName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-org&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;entityType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;stacks&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;preventative&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;stacks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;production&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;routingProject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-app&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;staging&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;routingProject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-app&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;policyPacks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;cis-aws&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;CIS AWS Foundations Benchmark&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;versionTag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1.5.0&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumiservice&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/pulumiservice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productionPolicies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PolicyGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;production-policies&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;production-compliance&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;organizationName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;my-org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;entityType&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;stacks&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;preventative&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;stacks&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;production&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;routingProject&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;my-app&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;staging&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;routingProject&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;my-app&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;policyPacks&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cis-aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;CIS AWS Foundations Benchmark&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;version&lt;/span&gt;: &lt;span class="kt"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;versionTag&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1.5.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h3 id="example-account-based-policy-group"&gt;Example: Account-Based Policy Group&lt;/h3&gt;
&lt;p&gt;Apply compliance policies to your cloud accounts for resource governance:&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="yaml,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="yaml" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;insights-policy-group&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Insights account&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;aws-insights&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumiservice:InsightsAccount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;organizationName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-org&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;accountName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;production-aws&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;insights/aws-credentials&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Policy group targeting the Insights account&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cloud-compliance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumiservice:PolicyGroup&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;cloud-resource-compliance&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;organizationName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-org&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;entityType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;accounts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;audit&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;${aws-insights.accountName}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;policyPacks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-security-best-practices&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;AWS Security Best Practices&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumiservice&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/pulumiservice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Insights account
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;awsInsights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InsightsAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;aws-insights&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;organizationName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;my-org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;accountName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;production-aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;insights/aws-credentials&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Policy group targeting the Insights account
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cloudCompliance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PolicyGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;cloud-compliance&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cloud-resource-compliance&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;organizationName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;my-org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;entityType&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;accounts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;audit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;awsInsights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accountName&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;policyPacks&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws-security-best-practices&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;AWS Security Best Practices&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;version&lt;/span&gt;: &lt;span class="kt"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h2 id="querying-policy-packs"&gt;Querying Policy Packs&lt;/h2&gt;
&lt;p&gt;Use the &lt;code&gt;getPolicyPacks&lt;/code&gt; and &lt;code&gt;getPolicyPack&lt;/code&gt; data sources to discover available policy packs in your organization:&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="yaml,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="yaml" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;policy-packs-query&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# List all available policy packs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;availablePacks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::invoke&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumiservice:getPolicyPacks&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;organizationName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-org&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;return&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;policyPacks&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;policyPacks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${availablePacks}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumiservice&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/pulumiservice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// List all available policy packs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;availablePacks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getPolicyPacksOutput&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;organizationName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;my-org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;policyPacks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;availablePacks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;policyPacks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h2 id="getting-started"&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;To start using these new resources:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update the Pulumi Service Provider&lt;/strong&gt; to the latest version:&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="typescript,python,go,csharp,yaml" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm install @pulumi/pulumiservice@latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install --upgrade pulumi-pulumiservice
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go get github.com/pulumi/pulumi-pulumiservice/sdk/go/pulumiservice@latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet add package Pulumi.PulumiService
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="yaml" mode=""&gt;&lt;p&gt;No package installation needed for YAML - just use the resources directly.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h2 id="learn-more"&gt;Learn More&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/registry/packages/pulumiservice/"&gt;Pulumi Service Provider documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/insights/"&gt;Pulumi Insights documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/insights/policy/"&gt;Policy as Code documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;rsquo;re excited to see how you use these new capabilities to improve visibility and governance across your cloud infrastructure. As always, we welcome your feedback in our &lt;a href="https://slack.pulumi.com/"&gt;Community Slack&lt;/a&gt; or on &lt;a href="https://github.com/pulumi/pulumi-pulumiservice"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</description><author>Pulumi Insights Team</author><category>features</category><category>pulumi-cloud</category><category>policy-as-code</category></item><item><title>New in Pulumi IaC: `replacementTrigger` Resource Option</title><link>https://www.pulumi.com/blog/triggering-resource-replacements/</link><pubDate>Thu, 22 Jan 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/triggering-resource-replacements/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/triggering-resource-replacements/index.png" /&gt;
&lt;p&gt;Pulumi IaC gives us a declarative interface to updates. When we perform an update, Pulumi calculates the difference between your currently deployed infrastructure and what is being proposed, then deploys only what is required to migrate from the old state to the new state. Normally, this is exactly what we want: we minimize the amount of work required to perform the update, and don’t recreate anything unnecessarily. However, every now and then, we want to override this behavior.&lt;/p&gt;
&lt;p&gt;Recently, we talked about the new &lt;a href="https://www.pulumi.com/blog/dependent-resource-replacements/"&gt;&lt;code&gt;replaceWith&lt;/code&gt;&lt;/a&gt; option, which allows us to tell Pulumi that any replacement of one resource should always trigger a replacement of another (for example, if the database is replaced, we should replace our application server). Today, we’re going to take this idea one step further and talk about another new feature that gives us even more control over this process: replacement triggers.&lt;/p&gt;
&lt;h2 id="forcing-replacements"&gt;Forcing replacements&lt;/h2&gt;
&lt;p&gt;Let’s imagine we have a resource that, upon creation, generates some private keys. If that’s all the resource does, it probably isn’t ever going to change as far as Pulumi’s concerned: we wanted the resource before, and we want it after, so there is no change and no need to replace the resource that is already live. Now, let’s imagine that we want to cycle these private keys every month. How do we tell Pulumi that, if this update happens more than two weeks after the last time this resource was created, we want to recreate it?&lt;/p&gt;
&lt;p&gt;As another example, perhaps we want to replace a resource every time some external version number is bumped. Let’s imagine a documentation server may need to be replaced every time a new version of an API is made available. We could use the &lt;code&gt;--replace&lt;/code&gt; flag each time, but this process is error-prone to do manually, and would incur a maintenance burden to automate.&lt;/p&gt;
&lt;h2 id="defining-replacement-triggers"&gt;Defining replacement triggers&lt;/h2&gt;
&lt;p&gt;In essence, a replacement trigger is just a value attached to the resource as metadata. However, whenever this value changes between updates, it will trigger a replace operation on the given resource, regardless of whether anything else has changed.&lt;/p&gt;
&lt;p&gt;Let’s take our previous example: we want something to be replaced every month. With replacement triggers, we can solve this by representing the current year and month as a string:&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="typescript,python,go,csharp,java" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keyManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;KeyManagerResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;key-manager&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;replacementTrigger&lt;/span&gt;: &lt;span class="kt"&gt;today.getMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;key_manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KeyManagerResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;key-manager&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResourceOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;replacement_trigger&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;today&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%d-%d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Month&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Year&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;keyManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;NewKeyManagerResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;key-manager&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;KeyManagerResourceArgs&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReplacementTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="java" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LocalDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%d-%d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMonthValue&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getYear&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;keyManager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KeyManagerResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;key-manager&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KeyManagerResourceArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomResourceOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replacementTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$&amp;#34;{today.Month}-{today.Year}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;keyManager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KeyManagerResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;key-manager&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KeyManagerResourceArgs&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CustomResourceOptions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ReplacementTrigger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;When we run this update for the first time, the replacement trigger will be persisted to the Pulumi state. Each time we run an update, we’ll re-calculate the date string, and compare it against the current string. Finally, when we run the update again next month, and the date string no longer matches, our &lt;code&gt;key-manager&lt;/code&gt; will be replaced and our new keys will be generated!&lt;/p&gt;
&lt;h2 id="next-steps"&gt;Next steps&lt;/h2&gt;
&lt;p&gt;This feature is fully supported across all our SDKs as of v3.215.0. For more information about resource options, see the &lt;a href="https://www.pulumi.com/docs/iac/concepts/resources/options/"&gt;resource options documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and feel free to reach out with any questions via &lt;a href="https://github.com/pulumi/pulumi"&gt;GitHub&lt;/a&gt;, &lt;a href="https://x.com/pulumicorp"&gt;X&lt;/a&gt;, or our &lt;a href="https://slack.pulumi.com/"&gt;Community Slack&lt;/a&gt;.&lt;/p&gt;</description><author>Tom Harding</author><category>features</category><category>infrastructure-as-code</category><category>releases</category></item><item><title>Neo: Zero-downtime migration from CDK, Terraform &amp; Azure ARM</title><link>https://www.pulumi.com/blog/neo-migration/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/neo-migration/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-migration/index.png" /&gt;
&lt;p&gt;The barrier to migrating to Pulumi has always been the infrastructure you already have. Your existing resources can&amp;rsquo;t be disrupted, and manually importing them into a new tool is risky and time-consuming. Today, we&amp;rsquo;re excited to share how Neo removes this barrier entirely with automated, zero-downtime migration to Pulumi from AWS CDK, AWS CloudFormation, Terraform, CDKTF, and Azure ARM templates.&lt;/p&gt;
&lt;h2 id="why-iac-migrations-are-hard"&gt;Why IaC migrations are hard&lt;/h2&gt;
&lt;p&gt;The promise of Infrastructure as Code is that your code perfectly describes your running infrastructure. But switching IaC tools breaks this promise in dangerous ways.&lt;/p&gt;
&lt;p&gt;When you rewrite your infrastructure code in a new tool, you have two choices, both problematic. You can destroy and recreate all your resources to match the new code, accepting downtime and risk. Or you can try to import existing resources, which requires perfect knowledge of how every resource maps between the old and new systems. Many teams get stuck here, wanting Pulumi&amp;rsquo;s modern platform but unable to safely make the switch.&lt;/p&gt;
&lt;h2 id="neos-insight-state-knowledge-enables-perfect-migrations"&gt;Neo&amp;rsquo;s insight: State knowledge enables perfect migrations&lt;/h2&gt;
&lt;p&gt;The key to safe migration isn&amp;rsquo;t just converting code - it&amp;rsquo;s understanding the complete relationship between your existing IaC tool&amp;rsquo;s state and your actual cloud resources. Each IaC tool maintains this relationship differently: CDK through CloudFormation stacks, Terraform/CDKTF through state files, and ARM through Azure deployments. But they all have complete knowledge of what they manage.&lt;/p&gt;
&lt;p&gt;Neo leverages this existing state knowledge to orchestrate perfect resource transitions. Instead of asking you to manually find resource IDs and construct migration commands, Neo reads your current tool&amp;rsquo;s state, discovers every resource&amp;rsquo;s physical identity, and brings them under Pulumi management. This isn&amp;rsquo;t just automation - it&amp;rsquo;s using the source tool&amp;rsquo;s own knowledge against the migration problem.&lt;/p&gt;
&lt;p&gt;In practice, this means Neo can bridge the gap between how tools name resources and where they actually live. A Lambda function that CDK knows as &lt;code&gt;OrderHandler9I0J1K2L&lt;/code&gt; actually exists in AWS as &lt;code&gt;my-app-OrderHandler-9I0J1K2L&lt;/code&gt;, while a Terraform resource at address &lt;code&gt;aws_instance.web[2]&lt;/code&gt; maps to EC2 instance &lt;code&gt;i-0abc123def456&lt;/code&gt;. Neo understands these mappings and handles the complex cases like composite IDs (&lt;code&gt;FunctionName|StatementId&lt;/code&gt;), resource references, and dependency chains that must be migrated in order.&lt;/p&gt;
&lt;p&gt;Because Neo uses the source tool&amp;rsquo;s own state knowledge, your infrastructure doesn&amp;rsquo;t change at all during migration. Not a single resource is modified, recreated, or even touched. We&amp;rsquo;re simply transferring ownership from one IaC tool to another.&lt;/p&gt;
&lt;p&gt;This approach delivers three critical guarantees:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Zero downtime&lt;/strong&gt;: Resources are never deleted or recreated&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero risk&lt;/strong&gt;: Since nothing changes, you can abandon the migration at any point without consequence&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero surprises&lt;/strong&gt;: Preview confirms no infrastructure changes before you commit&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="migration-in-action-four-tools-one-approach"&gt;Migration in action: Four tools, one approach&lt;/h2&gt;
&lt;p&gt;Neo adapts its migration strategy to each tool&amp;rsquo;s unique characteristics while maintaining the same zero-downtime guarantee. Let&amp;rsquo;s explore how Neo handles migrations from each major IaC tool.&lt;/p&gt;
&lt;h2 id="aws-cdk-to-pulumi"&gt;AWS CDK to Pulumi&lt;/h2&gt;
&lt;p&gt;For teams using AWS CDK, Neo leverages the CloudFormation layer that underpins CDK deployments. CDK&amp;rsquo;s architecture actually makes migration straightforward: since CDK synthesizes to CloudFormation templates, Neo can read the deployed stacks directly to understand every resource and its configuration. For detailed migration steps, see our &lt;a href="https://www.pulumi.com/docs/iac/guides/migration/migrating-to-pulumi/from-cdk/"&gt;CDK migration guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The challenge with CDK migrations isn&amp;rsquo;t the CloudFormation layer - it&amp;rsquo;s the cryptic resource naming. CDK generates logical IDs like &lt;code&gt;OrdersTableA7B2C3D4&lt;/code&gt; that map to physical resources with completely different names. These mappings are buried in CloudFormation metadata, and getting them wrong means either orphaning resources or accidentally creating duplicates. Neo navigates this complexity by reading CloudFormation&amp;rsquo;s own stack outputs and resource metadata, discovering the exact physical ID for every logical resource.&lt;/p&gt;
&lt;p&gt;CDK also introduces complexity through its construct hierarchy. A single high-level construct might expand into dozens of CloudFormation resources, each with dependencies and references to others. Neo preserves these relationships during migration, ensuring that IAM roles still reference the right Lambda functions, API Gateway deployments still point to the correct stages, and security groups maintain their exact rules. The migration completes with your infrastructure unchanged and Pulumi&amp;rsquo;s preview confirming zero modifications.&lt;/p&gt;
&lt;a href="https://app.pulumi.com/neo?prompt=Leverage&amp;#43;the&amp;#43;cdk-to-pulumi&amp;#43;skill&amp;#43;to&amp;#43;migrate&amp;#43;my&amp;#43;CDK&amp;#43;application&amp;#43;to&amp;#43;a&amp;#43;Pulumi&amp;#43;application" class="neo-card"&gt;
&lt;div class="neo-card-content"&gt;
&lt;div class="neo-card-icon"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular" fill="currentColor" role="img" aria-label="Pulumi Neo AI icon"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#c-pulumi-neo-regular"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;div class="neo-card-text"&gt;
&lt;span class="neo-card-subtitle"&gt;Start a Neo task&lt;/span&gt;
&lt;span class="neo-card-title"&gt;Migrate your CDK application&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="neo-card-arrow"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--bold" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-caret-right-bold"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="aws-cloudformation-to-pulumi"&gt;AWS CloudFormation to Pulumi&lt;/h2&gt;
&lt;p&gt;For teams using CloudFormation directly (rather than through CDK), Neo provides a streamlined migration path. CloudFormation stacks contain complete resource metadata - every resource&amp;rsquo;s logical ID maps to a physical resource in AWS, and CloudFormation tracks these relationships in its stack state. Neo reads this state directly to build a complete picture of your infrastructure. For detailed migration steps, see our &lt;a href="https://www.pulumi.com/docs/iac/guides/migration/migrating-to-pulumi/from-cloudformation/"&gt;CloudFormation migration guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The main challenge with CloudFormation migrations is the template language itself. CloudFormation templates use intrinsic functions like &lt;code&gt;!Ref&lt;/code&gt;, &lt;code&gt;!GetAtt&lt;/code&gt;, and &lt;code&gt;!Sub&lt;/code&gt; that create implicit dependencies between resources. A security group might reference a VPC using &lt;code&gt;!Ref MyVpc&lt;/code&gt;, while a Lambda function&amp;rsquo;s role uses &lt;code&gt;!GetAtt LambdaRole.Arn&lt;/code&gt;. Neo evaluates these expressions against the actual deployed stack to resolve every reference to its concrete value.&lt;/p&gt;
&lt;p&gt;CloudFormation also supports features like conditionals, mappings, and nested stacks that add layers of indirection. Neo handles these by examining what actually got deployed rather than trying to interpret every possible template path. The result is Pulumi code that manages your exact infrastructure configuration - not a theoretical interpretation of your template. The migration completes with &lt;code&gt;pulumi preview&lt;/code&gt; confirming zero changes to your running resources.&lt;/p&gt;
&lt;a href="https://app.pulumi.com/neo?prompt=Leverage&amp;#43;the&amp;#43;cloudformation-to-pulumi&amp;#43;skill&amp;#43;to&amp;#43;migrate&amp;#43;my&amp;#43;CloudFormation&amp;#43;stack&amp;#43;to&amp;#43;a&amp;#43;Pulumi&amp;#43;application" class="neo-card"&gt;
&lt;div class="neo-card-content"&gt;
&lt;div class="neo-card-icon"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular" fill="currentColor" role="img" aria-label="Pulumi Neo AI icon"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#c-pulumi-neo-regular"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;div class="neo-card-text"&gt;
&lt;span class="neo-card-subtitle"&gt;Start a Neo task&lt;/span&gt;
&lt;span class="neo-card-title"&gt;Migrate your CloudFormation stack&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="neo-card-arrow"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--bold" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-caret-right-bold"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="terraform-to-pulumi"&gt;Terraform to Pulumi&lt;/h2&gt;
&lt;p&gt;Terraform and CDKTF migrations require two transformations: converting state to establish Pulumi&amp;rsquo;s connection to your resources, and transforming HCL configuration into Pulumi code. The state conversion is direct - Neo reads your Terraform state and converts it into Pulumi state, preserving the mappings between resource names and cloud IDs. This ensures Pulumi knows that &lt;code&gt;aws_instance.web[2]&lt;/code&gt; corresponds to EC2 instance &lt;code&gt;i-0abc123def456&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The code transformation analyzes your HCL to generate equivalent Pulumi code. Neo handles Terraform patterns like &lt;code&gt;count&lt;/code&gt; and &lt;code&gt;for_each&lt;/code&gt; loops, module structures, and resource dependencies, recreating them idiomatically in Pulumi. The generated code manages your existing infrastructure without modifications - &lt;code&gt;pulumi preview&lt;/code&gt; confirms zero changes. For complete migration instructions, see our &lt;a href="https://www.pulumi.com/docs/iac/guides/migration/migrating-to-pulumi/from-terraform/"&gt;Terraform migration guide&lt;/a&gt;.&lt;/p&gt;
&lt;a href="https://app.pulumi.com/neo?prompt=Leverage&amp;#43;the&amp;#43;terraform-migration&amp;#43;skill&amp;#43;to&amp;#43;migrate&amp;#43;my&amp;#43;Terraform&amp;#43;application&amp;#43;to&amp;#43;a&amp;#43;Pulumi&amp;#43;application" class="neo-card"&gt;
&lt;div class="neo-card-content"&gt;
&lt;div class="neo-card-icon"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular" fill="currentColor" role="img" aria-label="Pulumi Neo AI icon"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#c-pulumi-neo-regular"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;div class="neo-card-text"&gt;
&lt;span class="neo-card-subtitle"&gt;Start a Neo task&lt;/span&gt;
&lt;span class="neo-card-title"&gt;Migrate your Terraform application&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="neo-card-arrow"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--bold" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-caret-right-bold"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="azure-arm-to-pulumi"&gt;Azure ARM to Pulumi&lt;/h2&gt;
&lt;p&gt;ARM templates present unique migration challenges. Unlike CDK and Terraform, which maintain clear separation between code and state, ARM templates blur this line. The template is both the definition and, through deployment history, part of the state tracking. ARM&amp;rsquo;s template expression language, with its concat functions and resource ID constructors, makes it difficult to determine what resources actually exist until deployment time. For step-by-step migration guidance, see our &lt;a href="https://www.pulumi.com/docs/iac/guides/migration/migrating-to-pulumi/from-arm/"&gt;ARM migration guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Neo orchestrates ARM migrations through intelligent AI-driven conversion. When an ARM template uses functions like &lt;code&gt;concat(parameters('appName'), '-plan')&lt;/code&gt;, the conversion process evaluates these expressions using the actual parameter values to generate the correct resource names. Azure resource IDs follow predictable patterns - subscription IDs, resource groups, providers, and resource names - and Neo ensures these are correctly brought under Pulumi management using inline resource specifications directly in the generated code.&lt;/p&gt;
&lt;p&gt;The biggest challenge with ARM migrations is handling the implicit dependencies and resource provider quirks. An App Service might implicitly create a service plan, a SQL database requires a server that might be defined in a linked template, and child resources like application settings need separate migration steps. Neo understands these Azure-specific patterns and generates the appropriate Pulumi code to manage every resource. The migration completes with a zero-diff preview, confirming your exact Azure configuration is preserved while giving you a more maintainable, type-safe way to manage it going forward.&lt;/p&gt;
&lt;a href="https://app.pulumi.com/neo?prompt=Leverage&amp;#43;the&amp;#43;arm-to-pulumi&amp;#43;skill&amp;#43;to&amp;#43;migrate&amp;#43;my&amp;#43;ARM&amp;#43;application&amp;#43;to&amp;#43;a&amp;#43;Pulumi&amp;#43;application" class="neo-card"&gt;
&lt;div class="neo-card-content"&gt;
&lt;div class="neo-card-icon"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular" fill="currentColor" role="img" aria-label="Pulumi Neo AI icon"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#c-pulumi-neo-regular"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;div class="neo-card-text"&gt;
&lt;span class="neo-card-subtitle"&gt;Start a Neo task&lt;/span&gt;
&lt;span class="neo-card-title"&gt;Migrate your ARM template&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="neo-card-arrow"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--bold" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.70121449e0dde6f8c01ff68423fffaa0336ecc73c7bbc87506404126694ca58c.svg#p-caret-right-bold"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="the-architecture-powering-it-all"&gt;The architecture powering it all&lt;/h2&gt;
&lt;p&gt;While each tool requires specific handling, Neo&amp;rsquo;s core architecture remains consistent:&lt;/p&gt;
&lt;h3 id="universal-orchestration-layer"&gt;Universal orchestration layer&lt;/h3&gt;
&lt;p&gt;Neo acts as the intelligent migration coordinator, regardless of source tool:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Credential verification&lt;/strong&gt;: Ensures proper cloud credentials are configured in Pulumi ESC&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource inventory&lt;/strong&gt;: Builds a complete catalog of existing resources&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversion orchestration&lt;/strong&gt;: Manages the code transformation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State migration&lt;/strong&gt;: Brings existing resources under Pulumi management&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit trail generation&lt;/strong&gt;: Creates comprehensive migration reports&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="unified-state-management-engine"&gt;Unified state management engine&lt;/h3&gt;
&lt;p&gt;The state management engine works consistently across all tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maps source resource IDs to Pulumi&amp;rsquo;s state management&lt;/li&gt;
&lt;li&gt;Handles complex and composite resource identifiers&lt;/li&gt;
&lt;li&gt;Provides fallback strategies for edge cases&lt;/li&gt;
&lt;li&gt;Ensures idempotent operations&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="human-oversight"&gt;Human oversight&lt;/h3&gt;
&lt;p&gt;While Neo automates the heavy lifting, we maintain human checkpoints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review generated code before migrating resources&lt;/li&gt;
&lt;li&gt;Verify preview shows zero changes&lt;/li&gt;
&lt;li&gt;Approve the resulting pull request&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-this-means-for-your-team"&gt;What this means for your team&lt;/h2&gt;
&lt;p&gt;Migration friction no longer locks you into your current IaC tool. If you want Pulumi&amp;rsquo;s programming model, policy engine, and multi-cloud support, Neo gets you there without disrupting your infrastructure.&lt;/p&gt;
&lt;p&gt;Ready to migrate? Check out our migration guides for &lt;a href="https://www.pulumi.com/docs/iac/guides/migration/migrating-to-pulumi/from-cdk/"&gt;CDK&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/iac/guides/migration/migrating-to-pulumi/from-cloudformation/"&gt;CloudFormation&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/iac/guides/migration/migrating-to-pulumi/from-terraform/"&gt;Terraform&lt;/a&gt;, or &lt;a href="https://www.pulumi.com/docs/iac/guides/migration/migrating-to-pulumi/from-arm/"&gt;Azure ARM&lt;/a&gt;. Join us in the &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; or reach out to your account team for a guided migration session.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>pulumi-neo</category><category>aws</category><category>cdk</category><category>cloudformation</category><category>terraform</category><category>azure</category><category>arm</category><category>migration</category><category>ai</category><category>features</category></item></channel></rss>