Library / SDK
reactiveui/refit avatar
reactiveui/refit

Refit compiles a C# interface into HttpClient calls, and the docs keep a discrepancy list beside it

The automatic type-safe REST library for .NET. Refit turns a REST API into a C# interface and generates the HttpClient implementation, with support for HttpClientFactory, pluggable serializers and a testing package.

9,584 stars780 forksC#NOASSERTION

At a glance

What is it?
Refit generates HttpClient implementations from attributed C# interfaces at compile time, then splits client creation, serialization, reflection and testing into separate NuGet packages. The trade is a request body you never see in your own source, plus a published list of behavior that differs from hand-written HTTP code.
Who is it for?
Refit suits .NET teams that want a typed REST surface generated during the build and can live with a client body they never read in their own source. It does not suit teams who need to inspect or patch the request pipeline line by line, and it does not fit Native AOT apps that reach for Refit.Reflection.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • reactiveui/refit9,584 ★ · +11
Star history
Repository2026-09-222026-11-14
reactiveui/refit9.6k9.6k

11 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The generator emits the request code while your app compiles

The unit of work is an interface. You write methods on it, attach attributes that state the HTTP verb, the route template, headers and body, and the source generator builds the implementation as part of your app's own compilation. Not at first use, not through a runtime proxy you configure at startup. The runtime reflection path exists, but it is the opt-in package rather than the default, which tells you where the project thinks the balance lies. What your code keeps is everything around the call: the project is explicit that your app stays in control of HttpClient, cancellation and serialization, so the generated class sits between your interface and an HttpClient you construct and own. Query formatting and converters are declared the same way, as attributes, so a mistyped route template or a badly described query parameter becomes something the build sees.

Five packages to choose between before the first request

Refit ships to NuGet, and the choice is made at the package level. Refit carries the generated HTTP clients, request attributes, serializers and response types, together with the generator, interface analyzers and code fixes. Refit.HttpClientFactory adds registration with dependency injection and IHttpClientFactory, including generated-only and keyed registrations. Refit.Testing adds local replies and verification. Refit.Newtonsoft.Json and Refit.Xml add serializers. Refit.Reflection adds the runtime path. That is five decisions in front of the first request, and choosing the wrong serializer package costs you a second dependency and a second registration later. For the first request itself the project sends you to its documentation, which walks through one and links every topic to runnable examples under src/examples/Documentation, and those examples target .NET 10 and C# 14 unless the example states another target.

Refit.Reflection builds requests at runtime, which is why Native AOT cannot use it

The reflection package carries its own instruction in the package table: use generated clients for trimmed and Native AOT apps. Runtime reflection needs type metadata that a trimming step is free to remove and that ahead-of-time compilation bakes out, so a client built that way fails somewhere other than where it was registered. In exchange you skip the generator, which matters when a build cannot run one. The consequence is that this is not a global taste. Refit.Reflection is a reasonable pick in a JIT-compiled server or desktop app where reflection costs nothing measurable, and generated clients are the requirement in a trimmed or Native AOT deployment. Ship both from one codebase and you now maintain two client shapes for the same API. The package is marked optional rather than retired, so the boundary is a deployment constraint, not a roadmap.

System.Text.Json with generated metadata is the preferred path, the rest are extra packages

Serialization is settled before the first call. The stated preference is System.Text.Json with generated metadata, and the JSON surface has two entry points: contexts registered at client creation, and per-method JsonTypeInfo<T> parameters for methods that need the metadata of a specific type. Newtonsoft.Json and XML live in packages of their own, so an application whose models are already dressed in Newtonsoft attributes buys another serializer and another registration instead of switching. That is the shape of the whole project: one preferred default, and every deviation priced as a separate package plus configuration. The per-method parameter is the part that earns its keep on endpoints returning mixed or polymorphic payloads, where a single context registered at client creation has no room to describe what one method expects.

Refit.Testing can stall or drop a body, which is where streaming tests usually stop being useful

The testing package is specific about failure, not just about happy replies. It matches outgoing requests, supplies local replies, verifies calls and simulates network faults, then goes past what most fakes offer in three directions: streamed replies are released chunk by chunk instead of arriving in one piece, you choose how request bodies are captured, and simulated time belongs to the test rather than to the clock. Stalled or dropped bodies and streaming uploads get their own deterministic test story. For a team that means the paths that are hard to reproduce against a real server, a connection that opens and then goes quiet, a body that stops mid-transfer, a timeout that should fire after a known delay, become assertions instead of luck. The cost is that Refit.Testing is a separate package, so a test project referencing only Refit has none of it, and the request matcher has to describe exactly what your interfaces produce.

The return type on the interface is the decision your callers inherit

Refit accepts several shapes for a result: Task<T>, ValueTask<T>, IObservable<T> and response wrappers. Paging is lazy rather than eager, through PagedEnumerable<TPage, TItem>, which walks cursors, offsets and Link headers, so a page of results is not materialized before you ask for it. Streaming covers JSON arrays, JSON Lines and server-sent events. That range is the reason to use the library and also its sharpest edge in an existing codebase. Moving a hand-written HttpClient call onto an interface means picking one of these shapes, and every line that consumed the old call compiles against the new one. Turning a Task<T> into an IObservable<T> later is not a change you can hide behind a wrapper.

Retries and telemetry arrive as HttpClient handlers, and Refit only supplies the labels

Read the resilience entry closely: retries, timeouts and a fresh token for each retry come with Microsoft's resilience handler, while a separate HTTP retries topic covers HTTP-aware retries with provider header hints and deterministic tests. The same is true of telemetry, where OpenTelemetry spans and request-duration metrics are labelled by Refit method and route template. The mechanism is HttpClient's own pipeline, so anything you add there applies to every client you register, generated or reflection based, and Refit's contribution is the method name and route template on the span. The consequence is that adding retries is a decision about your handler configuration and about token issuance, since a fresh token per retry means the token is fetched again on each attempt rather than captured once. Header attributes, static or dynamic, and the request context for attaching local handler state exist to feed that same pipeline.

Three releases in five days on a main branch, and a discrepancy list to read before adopting

The repository is not archived and its last push was on 2026-11-01. The release list shows v16.4.0 on 2026-10-17, with v16.3.0 and v16.2.0 both dated 2026-09-26, so two of the three releases landed on the same day. The default branch is main. A LICENSE file, SECURITY.md and a codecov.yml sit at the root, and the package metadata carries no standard SPDX identifier, so an automated licence check has to resolve terms from the repository file rather than the manifest. The adoption question has an answer waiting on the site: a why-use-Refit page sets the generated interface beside equivalent manual HTTP code and its trade-offs, and known behavior discrepancies are recorded next to the APIs they affect. That page is the closest thing to a migration guide, and it is where you find out what a hand-written call will not survive the move.

Editorial conclusion

Refit suits .NET teams that want a typed REST surface generated during the build and can live with a client body they never read in their own source. It does not suit teams who need to inspect or patch the request pipeline line by line, and it does not fit Native AOT apps that reach for Refit.Reflection. Verify three things before moving an endpoint across: which return type the interface commits you to, since Task<T>, ValueTask<T>, IObservable<T> and the response wrappers are all fixed at the declaration and every caller compiles against that choice; whether your models need the preferred System.Text.Json with generated metadata or one of the separate Newtonsoft.Json and Xml packages; and which known behavior discrepancies the website records beside the specific APIs you plan to move.

Frequently asked questions

What is Refit in C#?

Refit turns a C# interface into an HTTP client. Attributes on the interface methods describe the request method, URL, headers and body, and the source generator builds the implementation while your app compiles. Your app keeps control of HttpClient, cancellation and serialization.

What is Refit for .NET?

It is the automatic type-safe REST library for .NET, distributed as several NuGet packages. Refit holds the generated clients, attributes, serializers and response types, Refit.HttpClientFactory adds IHttpClientFactory registration, Refit.Testing adds local replies and fault simulation, and Refit.Newtonsoft.Json, Refit.Xml and Refit.Reflection cover serializers and runtime reflection.

How do I install Refit?

The project points to its NuGet packages and to its documentation, which walks through a first request and links each topic to runnable source examples under src/examples/Documentation. Those examples use .NET 10 and C# 14 unless the example states another target.

Official sources

  1. License: MIT
  2. Project website
  3. reactiveui/refit on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/reactiveui-refit.svg)](https://hysenlabs.com/projects/reactiveui-refit)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/reactiveui-refit.svg)](https://hysenlabs.com/projects/reactiveui-refit)

Was this useful?