Skip to content
DocsTry Aspire
DocsTry

YARP integration

YARP logo

This article is the reference for the Aspire YARP Hosting integration. It enumerates the AppHost APIs — with examples for both AppHost.cs and apphost.mts — that you use to model a YARP (Yet Another Reverse Proxy) resource in your AppHost project.

The YARP hosting integration models a YARP resource as the YarpResource type. To access this type and APIs, install the 📦 Aspire.Hosting.Yarp NuGet package in your AppHost project:

Terminal
aspire add yarp

This updates your aspire.config.json with the YARP hosting integration package:

aspire.config.json
{
"packages": {
"Aspire.Hosting.Yarp": "*"
}
}

In your AppHost, add a YARP resource and configure routes programmatically:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const catalogService = await builder.addProject(
'catalogservice',
'../CatalogService/CatalogService.csproj'
);
const basketService = await builder.addProject(
'basketservice',
'../BasketService/BasketService.csproj'
);
const gateway = await builder.addYarp('gateway');
await gateway.withConfiguration(async (yarp) => {
await yarp.addCatchAllRoute(catalogService);
await yarp.addRoute('/api/{**catch-all}', basketService);
});
await builder.build().run();

When Aspire adds a YARP resource to the AppHost, it creates a new containerized YARP instance using the mcr.microsoft.com/dotnet/nightly/yarp container image.

Tags reflect the latest defaults on the microsoft/aspire main branch, and may be newer than the version pinned by the package you install.

The YARP integration provides a fluent API for configuring routes, clusters, and transforms programmatically:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const catalogService = await builder.addProject(
'catalogservice',
'../CatalogService/CatalogService.csproj'
);
const basketService = await builder.addProject(
'basketservice',
'../BasketService/BasketService.csproj'
);
const gateway = await builder.addYarp('gateway');
await gateway.withConfiguration(async (yarp) => {
// Add catch-all route for frontend service
await yarp.addCatchAllRoute(catalogService);
// Add specific path route with transforms
(
await yarp.addRoute('/api/{**catch-all}', basketService)
).withTransformPathRemovePrefix('/api');
// Configure route matching
(await yarp.addRoute('/catalog/api/{**catch-all}', catalogService))
.withMatch({
path: '/catalog/api/{**catch-all}',
methods: ['GET', 'POST'],
})
.withTransformPathRemovePrefix('/catalog');
});
await builder.build().run();

Routes define how incoming requests are matched and forwarded to backend services.

ScenarioC#TypeScript
Catch-all route for a resourceAddRoute(resource)addCatchAllRoute(resource)
Route for a resourceAddRoute(path, resource)addRoute(path, resource)
Route for an external serviceAddRoute(path, externalService)addRoute(path, externalService)
Route for an endpointAddRoute(path, cluster)addRoute(path, cluster)
Route for a URL destinationAddRoute(path, destination)addRoute(path, destination)

TypeScript AppHosts use unified route helpers. Pass any supported target to addRoute(path, target) or addCatchAllRoute(target): a YARP cluster, endpoint, service-discovery resource, external service, or URL string.

apphost.mts
await gateway.withConfiguration(async (yarp) => {
const httpEndpoint = await catalogService.getEndpoint('http');
const externalApi = await builder.addExternalService(
'external-api',
'https://api.example.com'
);
const endpointCluster = await yarp.addClusterFromEndpoint(httpEndpoint);
await yarp.addRoute('/from-cluster/{**catch-all}', endpointCluster);
await yarp.addRoute('/from-endpoint/{**catch-all}', httpEndpoint);
await yarp.addRoute('/from-resource/{**catch-all}', catalogService);
await yarp.addRoute('/from-external/{**catch-all}', externalApi);
await yarp.addRoute('/from-url/{**catch-all}', 'https://api.example.net');
await yarp.addCatchAllRoute(catalogService);
});

Transforms modify requests and responses as they pass through the proxy:

apphost.mts
(await yarp.addRoute('/api/{**catch-all}', basketService))
.withTransformPathRemovePrefix('/api')
.withTransformPathPrefix('/v1')
.withTransformRequestHeader('X-Forwarded-Host', 'gateway.example.com')
.withTransformResponseHeader('X-Powered-By', 'YARP');

Common transform methods include:

  • Path transforms: WithTransformPathRemovePrefix, WithTransformPathPrefix, WithTransformPathSet; TypeScript uses withTransformPathRemovePrefix, withTransformPathPrefix, and withTransformPathSet.
  • Header transforms: WithTransformRequestHeader, WithTransformResponseHeader; TypeScript uses withTransformRequestHeader and withTransformResponseHeader.
  • Query transforms: WithTransformQueryParameter, WithTransformQueryRemoveParameter; TypeScript uses withTransformQueryValue, withTransformQueryRouteValue, and withTransformQueryRemoveKey.
  • Custom transforms: WithTransform or withTransform for custom transformation logic.

To configure the host port that the YARP resource is exposed on, use the host port API:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const gateway = await builder.addYarp('gateway').withHostPort({ port: 8080 });
await gateway.withConfiguration(async (yarp) => {
// Configure routes...
});
await builder.build().run();

The YARP integration automatically works with service discovery when targeting resources:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const catalogService = await builder.addProject(
'catalogservice',
'../CatalogService/CatalogService.csproj'
);
const gateway = await builder.addYarp('gateway');
await gateway.withConfiguration(async (yarp) => {
// Service discovery automatically resolves catalogservice endpoints
await yarp.addRoute('/catalog/{**catch-all}', catalogService);
});
await builder.build().run();

For external services, use AddExternalService or addExternalService:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const externalApi = await builder.addExternalService(
'external-api',
'https://api.example.com'
);
const gateway = await builder.addYarp('gateway');
await gateway.withConfiguration(async (yarp) => {
await yarp.addRoute('/external/{**catch-all}', externalApi);
});
await builder.build().run();

YARP can serve static files alongside proxied routes. Use the static files API to enable static file serving:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const staticServer = await builder.addYarp('static').withStaticFiles();
await builder.build().run();

For building frontend applications, you can use a Docker multi-stage build:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const frontend = await builder
.addYarp('frontend')
.withDockerfile('../npmapp')
.withStaticFiles();
await builder.build().run();

You can combine static file serving with dynamic routing:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const apiService = await builder.addProject(
'api',
'../ApiService/ApiService.csproj'
);
const gateway = await builder.addYarp('gateway').withStaticFiles();
await gateway.withConfiguration(async (yarp) => {
// API routes take precedence over static files
await yarp.addRoute('/api/{**catch-all}', apiService);
// Static files are served for all other routes
});
await builder.build().run();

When both the YARP gateway and backend services use HTTPS, configure HTTPS endpoints using WithHttpsEndpoint or withHttpsEndpoint and the developer certificate. YARP can proxy HTTPS-to-HTTPS when the backend service exposes an HTTPS endpoint:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
// Backend service with HTTPS
const razorPages = await builder
.addProject('razorpages', '../RazorPagesApp/RazorPagesApp.csproj')
.withHttpsEndpoint();
// YARP gateway proxying to the HTTPS backend
const gateway = await builder
.addYarp('gateway')
.withHttpsEndpoint()
.withHttpsDeveloperCertificate();
await gateway.withConfiguration(async (yarp) => {
await yarp.addRoute('/{**catch-all}', razorPages);
});
await builder.build().run();