What is the difference between IActionResult, ActionResult<T> and returning T directly?

Web API & REST ASP.NET Core APIs Intermediate 2–3 Yrs3–5 Yrs Conceptual 1 min read

Quick Answer

Return T directly for the simplest case — the framework serialises it as 200. Return IActionResult when the action produces different status codes (Ok, NotFound, BadRequest) but you lose the response type for tooling. ActionResult<T> is the best of both — you can return either a T or a status result, and Swagger infers the success type.

If the action always succeeds, I just return the object and let the framework serialise it. The moment I need more than one outcome — found versus not found — I need a result type. IActionResult works but it's opaque; Swagger can't tell what the 200 body looks like. ActionResult<T> fixes that: the signature declares the success type, and I can still return NotFound() or return BadRequest(). I annotate the other status codes with ProducesResponseType so the generated OpenAPI is accurate. In minimal APIs the equivalent is the typed Results<Ok<T>, NotFound> union.

  • public ActionResult<Order> Get(int id) => _svc.Find(id) is {} o ? o : NotFound();.
  • Add [ProducesResponseType(StatusCodes.Status404NotFound)] for the non-success codes so OpenAPI is complete.
  • Minimal APIs use Results<Ok<Order>, NotFound> (typed results) for the same benefit.
  • [ApiController] auto-converts invalid model state to a 400 ProblemDetails before your code runs.