<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>JavaScript | The .NET Blog</title><link>https://thedotnetblog.com/tags/javascript/</link><description>Articles, tutorials and insights from the .NET community.</description><generator>Hugo</generator><language>en</language><managingEditor>@thedotnetblog (The .NET Blog)</managingEditor><webMaster>@thedotnetblog</webMaster><lastBuildDate>Fri, 24 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://thedotnetblog.com/tags/javascript/index.xml" rel="self" type="application/rss+xml"/><item><title>Aspire 13.2 Gets Bun, Better Containers, and Less Debugging Friction</title><link>https://thedotnetblog.com/posts/emiliano-montesdeoca/aspire-132-bun-container-enhancements/</link><pubDate>Fri, 24 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/posts/emiliano-montesdeoca/aspire-132-bun-container-enhancements/</guid><description>Aspire 13.2 adds first-class Bun support for Vite apps, fixes Yarn reliability, and ships container improvements that make local dev behavior honest. Here's what actually changed and why it matters.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve been building .NET backends with JavaScript frontends in Aspire, 13.2 is the kind of update that quietly makes your day better. No splashy new paradigms. Just solid improvements to things that were mildly annoying.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s walk through what actually landed.&lt;/p&gt;
&lt;h2 id="bun-is-now-a-first-class-citizen"&gt;Bun is Now a First-Class Citizen&lt;/h2&gt;
&lt;p&gt;The headline feature: Bun support for Vite apps in Aspire. One fluent call, done.&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;// TypeScript AppHost
&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;builder&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;createBuilder&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;await&lt;/span&gt; &lt;span class="nx"&gt;builder&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;addViteApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;frontend&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./frontend&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;withBun&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;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;run&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 team already uses Bun — which you might, given its dramatically faster install times and startup — Aspire no longer makes you fight against the grain. Previously, Aspire assumed npm and you had to work around it. Now &lt;code&gt;.withBun()&lt;/code&gt; is a first-class option alongside &lt;code&gt;.withYarn()&lt;/code&gt; and the default npm behavior.&lt;/p&gt;
&lt;p&gt;Why does this matter? Because JavaScript tooling speed directly affects your inner dev loop. If your frontend takes 30 seconds to install dependencies every time you spin up a fresh environment, that adds up. Bun cuts that dramatically.&lt;/p&gt;
&lt;p&gt;The C# AppHost equivalents are documented at &lt;a href="https://aspire.dev/integrations/frameworks/javascript/#use-bun"&gt;aspire.dev&lt;/a&gt; if you prefer authoring in C# — all the same patterns apply.&lt;/p&gt;
&lt;h2 id="yarn-got-more-reliable"&gt;Yarn Got More Reliable&lt;/h2&gt;
&lt;p&gt;Bun gets the spotlight, but Yarn users get something arguably more impactful: fewer mysterious failures. Aspire 13.2 improves reliability for &lt;code&gt;withYarn()&lt;/code&gt; with &lt;code&gt;addViteApp()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These kinds of fixes don&amp;rsquo;t sound exciting until you&amp;rsquo;ve spent 20 minutes debugging why your Yarn-backed frontend resource wouldn&amp;rsquo;t start. Consider it fixed.&lt;/p&gt;
&lt;h2 id="container-publishing-you-can-actually-reason-about"&gt;Container Publishing You Can Actually Reason About&lt;/h2&gt;
&lt;p&gt;Two container improvements worth knowing:&lt;/p&gt;
&lt;h3 id="explicit-pull-policy"&gt;Explicit Pull Policy&lt;/h3&gt;
&lt;p&gt;Docker Compose publishing now supports &lt;code&gt;PullPolicy&lt;/code&gt;, including a &lt;code&gt;Never&lt;/code&gt; option:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ImagePullPolicy&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;./.modules/aspire.js&amp;#39;&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;builder&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;createBuilder&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;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addDockerComposeEnvironment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;compose&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;worker&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;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;worker&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;myorg/worker:latest&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;withImagePullPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ImagePullPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Never&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;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;run&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;This is the &amp;ldquo;please use the image I already built and leave the registry out of it&amp;rdquo; workflow. Super useful when iterating locally on images you&amp;rsquo;re building and publishing manually, or when your CI produces an image and you want Compose to use exactly that one without sneaking in a remote pull.&lt;/p&gt;
&lt;h3 id="postgresql-18-volumes-work-again"&gt;PostgreSQL 18+ Volumes Work Again&lt;/h3&gt;
&lt;p&gt;PostgreSQL 18 changed its internal data directory layout. This broke volume mapping in Aspire silently — your data volume would be set up but persistence wouldn&amp;rsquo;t actually work correctly. 13.2 fixes this.&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;const&lt;/span&gt; &lt;span class="nx"&gt;postgres&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;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addPostgres&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;postgres&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;withDataVolume&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;isReadOnly&lt;/span&gt;: &lt;span class="kt"&gt;false&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 you&amp;rsquo;re running PostgreSQL 18 or later with a data volume, upgrade to Aspire 13.2 and don&amp;rsquo;t think about it again.&lt;/p&gt;
&lt;h2 id="debugging-quality-of-life-improvements"&gt;Debugging Quality-of-Life Improvements&lt;/h2&gt;
&lt;p&gt;A few things that make stepping through an AppHost session less frustrating:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DebuggerDisplayAttribute on core types&lt;/strong&gt; — &lt;code&gt;DistributedApplication&lt;/code&gt;, resources, endpoint expressions now show useful values in the debugger instead of requiring you to drill into object trees&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better WaitFor failure messages&lt;/strong&gt; — when resources fail to start, the error context is actually helpful now&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;BeforeResourceStartedEvent&lt;/code&gt; fires at the right time&lt;/strong&gt; — only when a resource is actually starting, not on unrelated state transitions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;launchSettings.json&lt;/code&gt; is more resilient&lt;/strong&gt; — less chance of a malformed setting corrupting your dev startup&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these are individually earth-shattering, but collectively they remove friction from the debugging experience. If you&amp;rsquo;ve ever had to drill three levels deep into an Aspire resource object to figure out what endpoint it was using, the debugger display improvement alone is worth the update.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Aspire 13.2 is a focused quality release. Bun support is the headline, but the container and debugging improvements are what will make your day-to-day work smoother. Worth updating — especially if you&amp;rsquo;re on PostgreSQL 18 with data volumes.&lt;/p&gt;
&lt;p&gt;Full details in the &lt;a href="https://devblogs.microsoft.com/aspire/aspire-bun-support-and-container-enhancements/"&gt;original post by David Pine&lt;/a&gt; and the &lt;a href="https://aspire.dev/whats-new/aspire-13-2/"&gt;Aspire 13.2 what&amp;rsquo;s new docs&lt;/a&gt;.&lt;/p&gt;</content:encoded></item></channel></rss>