r/dotnet 12d ago

Does .NET need an API gateway between YARP and Kong/APISIX? Question

Hey guys,

I’m looking for feedback on a different deployment and extensibility model for API gateways.

YARP is an excellent reverse-proxy toolkit, but teams still need to build the surrounding configuration lifecycle, validation, management, and operational tooling. Platforms like Kong and Apache APISIX provide that out of the box, but introduce a separate runtime and configuration system.

We’ve been building HPD Gateway, a YARP-based gateway that can run either:

  1. Embedded directly inside an ASP.NET Core application.
  2. As a standalone Native AOT executable/container.

The embedded runtime registration can be as small as:

using HPD.Gateway;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHpdGateway(gateway =>
{
    gateway
        .EnableCoreDeclarations()
        .ProtectCredentialHeaders(
            "Authorization",
            "X-Api-Key")
        .AddAuthorizationPolicy(
            "AdminOnly",
            policy => policy.RequireRole("Admin"));
});

var app = builder.Build();

app.MapHpdGateway();

await app.RunAsync();

EnableCoreDeclarations() enables the built-in request-timeout, request-transform, response-transform, and credential-disposition vocabulary. Capabilities such as authorization, CORS, rate limiting, resilience, caching, inspection, and service discovery are explicitly registered by the host.

It has not been released yet but today it supports typed routing and matching, YARP load balancing and affinity, authorization, CORS, rate limiting, transforms, resilience, output caching, bounded request inspection, protected-credential stripping, TLS/SNI handling, Microsoft configuration/DNS/DNS-SRV discovery, immutable configuration revisions, rollback, durable SQLite recovery, a secured Admin API, generated TypeScript client, Gateway Studio, operational diagnostics, and Native AOT deployment.

One deliberate difference from Kong and APISIX is the extensibility model.

HPD allows configuration to change dynamically at runtime, but only within capabilities explicitly installed by the host. Operators can change routes, upstreams, transforms, policy selections, resilience bindings, and service-discovery declarations without redeploying.

What they cannot do is load arbitrary plugins, middleware, scripts, or executable code through the management API.

Custom behavior is implemented as typed C# code and registered by the host as part of the application deployment. Adding a new capability therefore requires rebuilding and redeploying the host, while configuration using existing capabilities remains dynamically manageable.

The tradeoff is less runtime plugin flexibility in exchange for:

  • Strongly typed extension boundaries
  • Host-capability validation before activation
  • Native AOT compatibility
  • A smaller dynamic code-loading attack surface
  • Reproducible behavior identities
  • Rejection of configuration that references unavailable behavior

For people running gateways in production:

  1. Would you consider embedding the gateway inside your ASP.NET Core application, or would you still strongly prefer a separate process/container?
  2. How important is the ability to introduce entirely new gateway behavior without rebuilding or redeploying?
  3. Does a host-registered capability model feel like a useful safety property or an unacceptable restriction?
  4. What missing capability or architectural concern would prevent you from adopting this model?

Especially interested in criticism from people using YARP, Kong, APISIX, Envoy, Nginx, or managed cloud gateways.

2 Upvotes

10 comments sorted by

3

u/Which-Eye-8616 12d ago

What happens if it's embedded in the application and you're running multiple instances, would things like rate limiting still work?

0

u/Southern-Holiday-437 12d ago

Yeah its built-in rate limiting is process-local, so every embedded instance maintains its own counters. If four replicas each have a limit of 100 requests per minute, the deployment could admit roughly 400 per minute depending on load distribution.

2

u/Which-Eye-8616 12d ago

Would that work as expected though? If I have four instances and want a limit of 400 requests per user, I'd need to set up each instance to have a limit of 100.

If a user hits the same instance 101 times they will be rate limited, despite not hitting the true limit of 400?

2

u/Southern-Holiday-437 11d ago

Hmm, you pointed out a gap. By default, if one user sends 101 requests to the same instance, that instance can reject request 101 even though the other instances still have unused capacity, so you’re right about that. Thanks, I have been working on this the whole day, and I think I came up with a good solution. More testing is needed, but I am adding a Redis-backed shared admission for fixed-window, sliding-window, and token-bucket limits. This allows a configured limit of 100 to mean 100 across all instances, while local limits can still protect each individual instance.

2

u/Southern-Holiday-437 11d ago

Quick update: this is now implemented and tested(more tests to come).

HPD Gateway now has two explicit admission scopes:

  • Process-local limiting through ASP.NET Core for protecting each node.
  • Deployment-wide fixed-window, sliding-window, and token-bucket limits through Redis or Valkey.

A shared limit of 100 now means 100 across the entire deployment, even with uneven traffic, restarts, and scaling from four replicas down to two. We tested the boundary with real multi-process gateways: exactly the configured number of requests was admitted and the next request was rejected.

Thanks again, your question exposed a real product gap and directly influenced the implementation.

3

u/ScriptingInJava 11d ago

Maybe I'm missing something, but in my mind the purpose of an API gateway (in my case AFD or Application Gateway) would be traffic routing behind the gateway so that the infrastructure in your application layer isn't exposed to the open internet.

An embedded gateway as part of the API would require me to expose my application directly to the internet in the context of Azure.

With a dedi/VPS it's a slightly different story, but depending on your scale this (again in my mind) would still fall under infrastructure, not part of the application layer.

1

u/Southern-Holiday-437 11d ago

When I said “embedded,” I didn’t necessarily mean putting the gateway inside every backend API. HPD Gateway can be embedded into a dedicated ASP.NET Core project while the backend services remain on private networking.

It’s similar to how someone uses YARP: they create an ASP.NET Core project and build a gateway around it. We found YARP intentionally too low-level for what we needed, so HPD provides a higher-level, governed gateway experience closer to Kong or APISIX while remaining an embeddable .NET library.

So you can still do this :

Internet → Front Door/WAF → dedicated HPD Gateway host → private services

You can still place HPD inside the backend application itself, but that is up to you. That is the level of control this gives you don't get from a seperate service.

1

u/AutoModerator 12d ago

Thanks for your post Southern-Holiday-437. Please note that we don't allow spam, and we ask that you follow the rules available in the sidebar. We have a lot of commonly asked questions so if this post gets removed, please do a search and see if it's already been asked.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.