Hosting a SPA in a C# Project: A Better Dev Experience with YARP Link to heading
Modern web development often means combining a .NET backend with a JavaScript single page application (SPA) frontend. But how do you make them play nicely together—especially during development?
The Challenge Link to heading
Microsoft’s SpaProxy
package is a common solution. In development, it intercepts requests, starts your SPA (like with npm run dev
), and redirects the browser to the SPA’s port. In production, the SPA is built into /wwwroot
and served as static files by your .NET app.
But there’s a catch: during development, the browser is redirected to a different port. If your SPA uses relative links to call the API, those calls can break—because the frontend and backend are now on different ports.
A Smoother Solution: YARP Reverse Proxy Link to heading
Enter YARP, a flexible reverse proxy for .NET. Instead of redirecting, YARP can transparently proxy requests to your SPA during development:
- Requests hit your .NET app first.
- If not handled by the backend, YARP proxies them to the SPA dev server.
- The browser stays on the same port, so relative API links just work.
This setup is only needed for development—production remains unchanged, with static files served from /wwwroot
.
Note: You will need to start your SPA development server (e.g., with npm run dev
or the appropriate command for your frontend framework) manually. YARP will proxy requests to it, but it does not start the SPA server for you.
Implementation Overview Link to heading
-
Add YARP to your project:
dotnet add package Yarp.ReverseProxy
-
Configure YARP in
Program.cs
orStartup.cs
to proxy unhandled requests:In your
appsettings.Development.json
, add a YARP configuration section:{ "ReverseProxy": { "Routes": { "spa": { "ClusterId": "spaCluster", "Match": { "Path": "{**catch-all}" } } }, "Clusters": { "spaCluster": { "Destinations": { "spaDestination": { "Address": "http://localhost:5173/" } } } } } }
In
Program.cs
, enable YARP only in development:var builder = WebApplication.CreateBuilder(args); // ...existing code... if (builder.Environment.IsDevelopment()) { builder.Services.AddReverseProxy() .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy")); } var app = builder.Build(); // ...existing code... if (app.Environment.IsDevelopment()) { app.MapReverseProxy(); } // ...existing code...
This setup ensures:
- The proxy is only active in development.
- All requests not handled by your .NET endpoints are forwarded to the SPA dev server.
- The proxy target is easily configurable via
appsettings.Development.json
.
-
Use environment checks: Only enable the proxy in development, so production stays secure and efficient.
Conclusion Link to heading
Using YARP for SPA development in .NET keeps your workflow smooth: no broken API links, no confusing redirects, and a setup that mirrors production. Give it a try for a better developer experience!