Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public static IResourceBuilder<NxAppResource> AddApp(this IResourceBuilder<NxRes
"npm" => "npx",
"yarn" => "yarn",
"pnpm" => "pnpx",
"bun" => "bunx",
_ => executionAnnotation.ExecutableName
})
.WithArgs(context =>
Expand Down Expand Up @@ -133,6 +134,7 @@ public static IResourceBuilder<TurborepoAppResource> AddApp(this IResourceBuilde
"npm" => "npx",
"yarn" => "yarn",
"pnpm" => "pnpx",
"bun" => "bunx",
_ => executionAnnotation.ExecutableName
})
.WithArgs(context =>
Expand Down Expand Up @@ -182,7 +184,7 @@ public static IResourceBuilder<NxResource> WithPackageManagerLaunch(this IResour
}
else
{
throw new InvalidOperationException($"The Nx workspace '{builder.Resource.Name}' is not configured with a package manager. Call WithNpm/WithYarn/WithPnpm first, or provide an explicit package manager.");
throw new InvalidOperationException($"The Nx workspace '{builder.Resource.Name}' is not configured with a package manager. Call WithNpm/WithYarn/WithPnpm/WithBun first, or provide an explicit package manager.");
}
}

Expand Down Expand Up @@ -219,7 +221,7 @@ public static IResourceBuilder<TurborepoResource> WithPackageManagerLaunch(this
}
else
{
throw new InvalidOperationException($"The Turborepo workspace '{builder.Resource.Name}' is not configured with a package manager. Call WithNpm/WithYarn/WithPnpm first, or provide an explicit package manager.");
throw new InvalidOperationException($"The Turborepo workspace '{builder.Resource.Name}' is not configured with a package manager. Call WithNpm/WithYarn/WithPnpm/WithBun first, or provide an explicit package manager.");
}
}

Expand Down Expand Up @@ -301,6 +303,21 @@ public static IResourceBuilder<NxResource> WithPnpm(this IResourceBuilder<NxReso
return builder;
}

/// <summary>
/// Configures the Nx workspace to use bun as the package manager and optionally installs packages before apps start.
/// </summary>
/// <param name="builder">The Nx workspace resource builder.</param>
/// <param name="install">When true, automatically installs packages before apps start. When false (default), only sets the package manager annotation without creating an installer resource.</param>
/// <param name="configureInstaller">A function to configure the installer resource builder.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<NxResource> WithBun(this IResourceBuilder<NxResource> builder, bool install = false, Action<IResourceBuilder<JavaScriptInstallerResource>>? configureInstaller = null)
{
ArgumentNullException.ThrowIfNull(builder);

AddMonorepoInstaller(builder, "bun", install, configureInstaller);
return builder;
}

/// <summary>
/// Configures the Turborepo workspace to use npm as the package manager and optionally installs packages before apps start.
/// </summary>
Expand Down Expand Up @@ -346,6 +363,21 @@ public static IResourceBuilder<TurborepoResource> WithPnpm(this IResourceBuilder
return builder;
}

/// <summary>
/// Configures the Turborepo workspace to use bun as the package manager and optionally installs packages before apps start.
/// </summary>
/// <param name="builder">The Turborepo workspace resource builder.</param>
/// <param name="install">When true, automatically installs packages before apps start. When false (default), only sets the package manager annotation without creating an installer resource.</param>
/// <param name="configureInstaller">A function to configure the installer resource builder.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<TurborepoResource> WithBun(this IResourceBuilder<TurborepoResource> builder, bool install = false, Action<IResourceBuilder<JavaScriptInstallerResource>>? configureInstaller = null)
{
ArgumentNullException.ThrowIfNull(builder);

AddMonorepoInstaller(builder, "bun", install, configureInstaller);
return builder;
}

private static void AddMonorepoInstaller<TResource>(
IResourceBuilder<TResource> builder,
string packageManager,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
namespace Aspire.Hosting;

/// <summary>
/// Tracks which JavaScript package manager was configured for a monorepo workspace (via WithNpm/WithYarn/WithPnpm).
/// Tracks which JavaScript package manager was configured for a monorepo workspace (via WithNpm/WithYarn/WithPnpm/WithBun).
/// </summary>
/// <param name="packageManager">The name of the JavaScript package manager (e.g., "npm", "yarn", "pnpm").</param>
/// <param name="packageManager">The name of the JavaScript package manager (e.g., "npm", "yarn", "pnpm", "bun").</param>
public sealed class JavaScriptPackageManagerConfiguredAnnotation(string packageManager) : IResourceAnnotation
{
/// <summary>
/// Gets the name of the JavaScript package manager that was configured.
/// </summary>
public string PackageManager { get; } = packageManager;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ var app3 = turbo.AddApp("app3");

## Package Managers

Both Nx and Turborepo support yarn and pnpm package managers:
Both Nx and Turborepo support yarn, pnpm, and bun package managers:

- `.WithYarnPackageInstaller()` - uses yarn
- `.WithPnpmPackageInstaller()` - uses pnpm
- `.WithYarn(install: true)` - uses yarn
- `.WithPnpm(install: true)` - uses pnpm
- `.WithBun(install: true)` - uses bun
Comment on lines +49 to +53
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section was updated to recommend .WithYarn(install: true), .WithPnpm(install: true), etc., but the rest of MONOREPO.md still uses .WithYarnPackageInstaller() / .WithPnpmPackageInstaller() in the code samples, which don’t exist in the codebase. Please update the earlier examples and the “Package Installer” discussion to use the actual APIs (WithYarn(install: true), WithPnpm(install: true), WithBun(install: true), etc.) so the documentation is consistent and copy/paste-able.

Copilot uses AI. Check for mistakes.

> **Note**: npm support (`AddNpmApp`, `WithNpmPackageInstallation`) is now provided by [Aspire.Hosting.JavaScript](https://www.nuget.org/packages/Aspire.Hosting.JavaScript) starting with Aspire 13.

Expand Down Expand Up @@ -144,4 +145,3 @@ var nx = builder.AddNxApp("nx", workingDirectory: "../frontend")

// This is valid - you can install with pnpm but run apps with yarn
```

Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,15 @@ var turbo = builder.AddTurborepoApp("turbo", workingDirectory: "../frontend")
.WithPnpm()
.WithPackageManagerLaunch("pnpm"); // Uses 'pnpm' command

// Bun example
var bunRepo = builder.AddTurborepoApp("bun-repo", workingDirectory: "../frontend")
.WithBun()
.WithPackageManagerLaunch("bun"); // Uses 'bun' command
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Bun example, the comment says WithPackageManagerLaunch("bun") uses the bun command, but the implementation maps bun to bunx when generating the app command. Update the comment to reflect that the executable will be bunx (or adjust the example to pass "bunx" if that’s the intent).

Suggested change
.WithPackageManagerLaunch("bun"); // Uses 'bun' command
.WithPackageManagerLaunch("bun"); // Uses 'bunx' command

Copilot uses AI. Check for mistakes.

// Generated commands:
// Nx with yarn: yarn nx serve app1
// Turborepo with pnpm: pnpm turbo run dev --filter app1
// Turborepo with bun: bunx turbo run dev --filter app1
```

### Package installation with custom flags
Expand Down Expand Up @@ -84,4 +90,3 @@ https://learn.microsoft.com/dotnet/aspire/community-toolkit/hosting-nodejs-exten
## Feedback & contributing

https://github.com/CommunityToolkit/Aspire

Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public void NxResource_IsRunningState()
[InlineData("npm")]
[InlineData("yarn")]
[InlineData("pnpm")]
[InlineData("bun")]
public async Task Nx_WithPackageManagerLaunch_InfersFromInstallerWhenNotProvided(string packageManager)
{
var builder = DistributedApplication.CreateBuilder();
Expand All @@ -70,6 +71,7 @@ public async Task Nx_WithPackageManagerLaunch_InfersFromInstallerWhenNotProvided
"npm" => nxBuilder.WithNpm(),
"yarn" => nxBuilder.WithYarn(),
"pnpm" => nxBuilder.WithPnpm(),
"bun" => nxBuilder.WithBun(),
_ => throw new ArgumentOutOfRangeException(nameof(packageManager), $"Unsupported package manager: {packageManager}"),
}).WithPackageManagerLaunch();

Expand All @@ -93,6 +95,7 @@ public async Task Nx_WithPackageManagerLaunch_InfersFromInstallerWhenNotProvided
"npm" => "npx",
"yarn" => "yarn",
"pnpm" => "pnpx",
"bun" => "bunx",
_ => packageManager
}, nxAppResource.Command);
var nxAppArgs = await nxAppResource.GetArgumentListAsync();
Expand Down Expand Up @@ -178,6 +181,7 @@ public async Task Nx_NoWithPackageManagerLaunch_Defaults_AppCommandsIncludeNpxOr
[InlineData("npm")]
[InlineData("yarn")]
[InlineData("pnpm")]
[InlineData("bun")]
public async Task Nx_WithPackageManager_WithoutRunWith_DoesNotAffectAppExecution(string packageManager)
{
var builder = DistributedApplication.CreateBuilder();
Expand All @@ -189,6 +193,7 @@ public async Task Nx_WithPackageManager_WithoutRunWith_DoesNotAffectAppExecution
"npm" => nxBuilder.WithNpm(),
"yarn" => nxBuilder.WithYarn(),
"pnpm" => nxBuilder.WithPnpm(),
"bun" => nxBuilder.WithBun(),
_ => throw new ArgumentOutOfRangeException(nameof(packageManager))
};

Expand Down Expand Up @@ -273,6 +278,7 @@ public void Nx_WithPackageManagerLaunch_CalledTwiceWithDifferent_Throws()
[InlineData("npm")]
[InlineData("yarn")]
[InlineData("pnpm")]
[InlineData("bun")]
public async Task Nx_MultipleApps_AllInheritExecutionAnnotation(string packageManager)
{
var builder = DistributedApplication.CreateBuilder();
Expand All @@ -283,6 +289,7 @@ public async Task Nx_MultipleApps_AllInheritExecutionAnnotation(string packageMa
"npm" => nx.WithNpm(),
"yarn" => nx.WithYarn(),
"pnpm" => nx.WithPnpm(),
"bun" => nx.WithBun(),
_ => throw new ArgumentOutOfRangeException(nameof(packageManager))
};
nx = nx.WithPackageManagerLaunch();
Expand All @@ -304,6 +311,7 @@ public async Task Nx_MultipleApps_AllInheritExecutionAnnotation(string packageMa
"npm" => "npx",
"yarn" => "yarn",
"pnpm" => "pnpx",
"bun" => "bunx",
_ => throw new ArgumentOutOfRangeException(nameof(packageManager))
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public void TurborepoResource_IsRunningState()
[InlineData("npm")]
[InlineData("yarn")]
[InlineData("pnpm")]
[InlineData("bun")]
public async Task Turborepo_WithPackageManagerLaunch_InfersFromInstallerWhenNotProvided(string packageManager)
{
var builder = DistributedApplication.CreateBuilder();
Expand All @@ -70,6 +71,7 @@ public async Task Turborepo_WithPackageManagerLaunch_InfersFromInstallerWhenNotP
"npm" => turbo.WithNpm(),
"yarn" => turbo.WithYarn(),
"pnpm" => turbo.WithPnpm(),
"bun" => turbo.WithBun(),
_ => throw new ArgumentOutOfRangeException(nameof(packageManager), $"Unsupported package manager: {packageManager}"),
}).WithPackageManagerLaunch();

Expand All @@ -92,6 +94,7 @@ public async Task Turborepo_WithPackageManagerLaunch_InfersFromInstallerWhenNotP
"npm" => "npx",
"yarn" => "yarn",
"pnpm" => "pnpx",
"bun" => "bunx",
_ => packageManager
}, turboApp.Command);
var turboArgs = await turboApp.GetArgumentListAsync();
Expand Down Expand Up @@ -175,6 +178,7 @@ public async Task Turborepo_NoWithPackageManagerLaunch_Defaults_AppCommandsInclu
[InlineData("npm")]
[InlineData("yarn")]
[InlineData("pnpm")]
[InlineData("bun")]
public async Task Turborepo_WithPackageManager_WithoutRunWith_DoesNotAffectAppExecution(string packageManager)
{
var builder = DistributedApplication.CreateBuilder();
Expand All @@ -185,6 +189,7 @@ public async Task Turborepo_WithPackageManager_WithoutRunWith_DoesNotAffectAppEx
"npm" => turboBuilder.WithNpm(),
"yarn" => turboBuilder.WithYarn(),
"pnpm" => turboBuilder.WithPnpm(),
"bun" => turboBuilder.WithBun(),
_ => throw new ArgumentOutOfRangeException(nameof(packageManager))
};

Expand Down Expand Up @@ -280,6 +285,7 @@ public void Turborepo_WithPackageManagerLaunch_CalledTwiceWithSame_DoesNotThrow(
[InlineData("npm")]
[InlineData("yarn")]
[InlineData("pnpm")]
[InlineData("bun")]
public async Task Turborepo_MultipleApps_AllInheritExecutionAnnotation(string packageManager)
{
var builder = DistributedApplication.CreateBuilder();
Expand All @@ -290,6 +296,7 @@ public async Task Turborepo_MultipleApps_AllInheritExecutionAnnotation(string pa
"npm" => turbo.WithNpm(),
"yarn" => turbo.WithYarn(),
"pnpm" => turbo.WithPnpm(),
"bun" => turbo.WithBun(),
_ => throw new ArgumentOutOfRangeException(nameof(packageManager))
};
turbo = turbo.WithPackageManagerLaunch();
Expand All @@ -311,6 +318,7 @@ public async Task Turborepo_MultipleApps_AllInheritExecutionAnnotation(string pa
"npm" => "npx",
"yarn" => "yarn",
"pnpm" => "pnpx",
"bun" => "bunx",
_ => throw new ArgumentOutOfRangeException(nameof(packageManager))
};

Expand Down
Loading