This extension now provides built-in support for frontend monorepos using Nx and Turborepo.
When using monorepos, multiple applications share the same package.json and workspace setup. Previously, if you tried to run multiple apps with individual package installers, you would encounter race conditions:
// This causes race conditions - multiple installers for the same directory
var app1 = builder.AddYarnApp("app-1", "./Frontend", args: ["app1"])
.WithYarnPackageInstallation();
var app2 = builder.AddYarnApp("app-2", "./Frontend", args: ["app2"])
.WithYarnPackageInstallation();
var app3 = builder.AddYarnApp("app-3", "./Frontend", args: ["app3"])
.WithYarnPackageInstallation();Use the new monorepo-specific extension methods that create a shared package installer:
var nx = builder.AddNxApp("nx", workingDirectory: "../frontend")
.WithYarnPackageInstaller(); // Single shared installer
var app1 = nx.AddApp("app1");
var app2 = nx.AddApp("app2", appName: "my-app-2"); // Custom app name for nx serve
var app3 = nx.AddApp("app3");var turbo = builder.AddTurborepoApp("turbo", workingDirectory: "../frontend")
.WithPnpmPackageInstaller(); // Single shared installer
var app1 = turbo.AddApp("app1");
var app2 = turbo.AddApp("app2", filter: "custom-filter"); // Custom filter
var app3 = turbo.AddApp("app3");Both Nx and Turborepo support yarn, pnpm, and bun package managers:
.WithYarn(install: true)- uses yarn.WithPnpm(install: true)- uses pnpm.WithBun(install: true)- uses bun
Note: npm support (
AddNpmApp,WithNpmPackageInstallation) is now provided by Aspire.Hosting.JavaScript starting with Aspire 13.
Use WithPackageManagerLaunch() to configure which package manager command is used when running individual apps:
// Auto-infer from package installer annotation
var nx = builder.AddNxApp("nx", workingDirectory: "../frontend")
.WithYarnPackageInstaller()
.WithPackageManagerLaunch(); // Will use 'yarn' command
// Explicitly specify package manager (independent of installer)
var turbo = builder.AddTurborepoApp("turbo", workingDirectory: "../frontend")
.WithPnpmPackageInstaller()
.WithPackageManagerLaunch("yarn"); // Uses 'yarn' despite pnpm installer
// Without WithPackageManagerLaunch - uses default commands
var nxDefault = builder.AddNxApp("nx-default", workingDirectory: "../frontend");
nxDefault.AddApp("app1"); // Runs: nx serve app1 (no package manager prefix)Command Generation Examples:
WithPackageManagerLaunch("yarn")→yarn nx serve app1oryarn turbo run dev --filter app1WithPackageManagerLaunch("pnpm")→pnpm nx serve app1orpnpm turbo run dev --filter app1- No
WithPackageManagerLaunch()→nx serve app1orturbo run dev --filter app1
- Shared Installer: The top-level resource (
NxResourceorTurborepoResource) manages a single package installation - Individual Apps: Each app resource (
NxAppResourceorTurborepoAppResource) waits for the shared installer to complete - No Race Conditions: Only one package installer runs per workspace directory
- Command:
nx serve {appName} - The
appNameparameter controls which app Nx serves
- Command:
turbo run dev --filter {filter} - The
filterparameter controls which packages Turborepo builds/serves
If you're currently using the workaround pattern:
// Old workaround approach
var app1 = builder.AddYarnApp("app-1", "./Frontend", args: ["app1"])
.WithYarnPackageInstallation();
var app2 = builder.AddYarnApp("app-2", "./Frontend", args: ["app2"])
.WaitFor(app1); // Manual dependency
var app3 = builder.AddYarnApp("app-3", "./Frontend", args: ["app3"])
.WaitFor(app1); // Manual dependencyYou can migrate to:
// New monorepo approach
var nx = builder.AddNxApp("nx", workingDirectory: "./Frontend")
.WithYarnPackageInstaller()
.WithPackageManagerLaunch(); // Configure package manager for app execution
var app1 = nx.AddApp("app-1", appName: "app1");
var app2 = nx.AddApp("app-2", appName: "app2");
var app3 = nx.AddApp("app-3", appName: "app3");This provides cleaner syntax and automatic dependency management.
It's important to understand the difference between package installation and app execution:
- Package Installer (
.WithYarnPackageInstaller(),.WithPnpmPackageInstaller()) - Controls how packages are installed in the workspace - Package Manager for Apps (
.WithPackageManagerLaunch()) - Controls which command is used to run individual apps
var nx = builder.AddNxApp("nx", workingDirectory: "../frontend")
.WithPnpmPackageInstaller() // Install packages with: pnpm install
.WithPackageManagerLaunch("yarn"); // Run apps with: yarn nx serve app1
// This is valid - you can install with pnpm but run apps with yarn