# Chopper: a Dart HTTP client generator that produces typed request methods

> Chopper is an HTTP client generator for Dart and Flutter, built on source_gen and inspired by Retrofit, where you annotate a service class and the build step emits the client. It suits Dart teams that want typed requests and converters, and it is a poor fit for a project that would rather hand write its HTTP layer.

**lejard-h/chopper** — Chopper is an http client generator using source_gen and inspired from Retrofit.

- Repository: https://github.com/lejard-h/chopper
- Website: https://hadrien-lejard.gitbook.io/chopper
- Stars: 747 · Forks: 128
- Language: Dart
- License: NOASSERTION
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/lejard-h-chopper

## A generator that turns an annotated service class into a client

Chopper is described as an HTTP client generator for Dart and Flutter using source_gen and inspired by Retrofit. The Retrofit comparison is the clearest description of the design: instead of writing an HTTP client by hand, you declare an abstract service with a method per endpoint and let a code generator emit the implementation.

That means the generator is a build-time dependency, not a runtime one. source_gen is the Dart build-time library the generator is built on, so the tool runs as part of the Dart build step and writes a Dart file into your project. Your application then depends on the generated code and on the runtime package that supports it.

The repository layout shows the pieces as separate directories. chopper/ is the runtime package that the generated code depends on. chopper_generator/ is the generator itself, published under its own name. chopper_built_value/ is a separate package carrying the built_value flavour of the converter. converters/ holds the converter implementations, with a converters/converters.md document among them. tool/ holds tooling, and skills/ is a directory whose purpose the repository listing does not describe.

This split matters for upgrades. The generator and the runtime have independent version numbers and are released together but separately, with chopper_generator-v8.7.1 and chopper-v8.7.1 both dated 2026-10-03, and the previous generator release at 8.7.0 on 2026-07-15. A mismatch between the generator version in your build dependencies and the runtime version in your dependencies is a realistic failure mode here.

## Converters and interceptors are the extension seams

Two extension points are documented at the top level of the repository, and they are where most of the real complexity in a Chopper based project lives.

The converters are the serialization layer. A converter decides how a Dart object becomes a request body and how a response body becomes a Dart object. The repository ships at least two flavours, and the example directory makes the difference visible: one example is named main_json_serializable.dart and another is named main_built_value.dart. The built_value variant is not a small detail in that example set, since built_value and json_serializable are competing Dart object serialization approaches and a project will usually have already picked one. The chopper_built_value/ package exists so that the built_value case is a package rather than a rewrite.

The interceptors are the other seam, and they are documented in interceptors.md at the repository root. An interceptor sits between the generated method and the HTTP client, which is the natural place for authentication headers, logging, retry policy or request identifiers. The interceptor list at the top level includes requests.md as well, so the request feature set, the converter set and the interceptor set are each documented as a first class topic rather than as an afterthought.

The documentation host is a GitBook at hadrien-lejard.gitbook.io/chopper, and SUMMARY.md at the root is the table of contents that drives it. That is a fair amount of documentation surface for a library whose README is short, which is a point in favour of a team that intends to read it before adopting.

## The example project as the real tutorial

The README itself does not contain a code example. It points at three example files instead: main_json_serializable.dart for a JSON serializable converter, main_built_value.dart for the built value converter, and main_request_features.dart for what the request layer can do.

The example directory is set up like a small real application rather than a snippet. It has a Makefile, an analysis_options.yaml, a build.yaml, a pubspec.yaml, and separate bin/ and lib/ directories. The presence of a Makefile suggests the build step is invoked by a task rather than by hand, and build.yaml is consistent with a repository that keeps generated sources under control.

The build.yaml file deserves a note, because it is the file that makes a generator-based library work in a normal repository. A generated client is derived from an annotated service class, so if the generated file is committed to version control and the annotation changes, the two can drift apart and the compiler will complain about a stale class. A build configuration that regenerates the client as part of the build removes that class of problem. The repository does not document the contents of these files in the README, so a team adopting Chopper should read them in the example directory rather than assume a default.

The installation route itself is straightforward and is the standard Dart one. The README refers to the installation guide on pub.dev and to a Getting started document, and the package is listed on pub.dev as chopper. There is no compiled component, no native toolchain and no code generation command described in the README, because the generation is driven by the Dart build system through source_gen.

## Where the documentation stops and you have to read the code

Several things a buyer would want to know are simply not in the repository's own text, and the omissions are consistent enough to name as a group.

The README does not state which Dart SDK versions are supported, and the pub package page rather than the repository is the documented place to check that. It does not name the minimum version of source_gen or build_runner required. It does not document how a generated client handles errors, whether a non-2xx response throws, or how the response type is expressed, and the requests.md document is where that would live. It does not say how authentication headers are attached, which is the interceptor's job. And it does not describe any retry, caching or logging behaviour at all.

The absence of an explicit error model is the one that matters most for a production client. Generated clients typically return a Response object with an isSuccessful flag rather than throwing, but the repository does not state that, so it should be verified against the requests documentation and the example code rather than assumed.

The repository does contain the usual governance files, which tells you something about how the project is run. There is a CODE-OF-CONDUCT.md, a CONTRIBUTING.md, a SECURITY.md, and an .all-contributorsrc with the all-contributors specification. There is also a mono_repo.yaml, which indicates that the multiple packages in this repository are managed as a monorepo with coordinated versioning rather than as independent repositories, and a codecov.yml for coverage reporting, alongside a Dart CI workflow badge.

## The custom licence needs to be read before the package ships

The licence field for this repository is recorded as other, with the note that it is a custom licence GitHub cannot classify and that the LICENSE file at the root is the reference. That is a materially different situation from the Apache, MIT or BSD licences that most Dart packages carry, and it deserves attention before an application depends on it.

The point is not that the terms are unfavourable, since this article cannot judge them. The point is that they are not standard, and a standard licence is something a legal team can approve once for the whole organisation. A custom licence has to be read, and possibly negotiated, per project.

There is a second reason to look at the file closely. Chopper is a code generator, so the licence of the generator determines the licence of the code it writes into your project. If the terms are reciprocal or impose attribution on generated output, that propagates into code you own, which is a different question from the licence of the runtime package you depend on.

The SECURITY.md file at the root suggests the project has a process for reporting vulnerabilities. That matters for a package that sits on the path of every outgoing HTTP request in a Dart application, and it is the file to point at if you need to know how a security issue would be reported and handled.

## How a generated client compares with a hand written one

The alternative worth naming is the hand written client, and the difference in approach is straightforward.

A hand written client in Dart is a class with a method per endpoint. Each method builds a Uri, attaches headers, picks a body converter, sends the request through an http.Client, and maps the response. It is entirely under your control, the dependency count is one, and there is no build step to configure. What you give up is that every URL is a string, every request body is an untyped map, and every response is a dynamic that fails at runtime rather than at compile time.

Chopper moves that work to build time. The annotated service describes the endpoint once, and the generator produces the request building and the response mapping, so a change to a response field becomes a compile error in the consuming code rather than a runtime cast failure.

The tradeoff runs the other way too. The generator adds a build-time dependency and a code generation step to every developer checkout and every CI run, and the generated file has to be kept in sync with the annotated class. A team with a strict continuous integration pipeline that avoids code generation, or a codebase with only a couple of endpoints, will often get more from a hand written client.

There is also a middle path worth noting. The runtime package and the generator are separable, and the converters are separate packages, so a project can adopt the request and converter layer without committing to the full generator workflow. That is a smaller decision than adopting the generator itself.

## Maintenance state and the release cadence you can rely on

The repository is not archived, and the last push was on 2026-10-19, two days before this article. The default branch is develop, with master also referenced in badge links and in the example file paths, which tells you the project works on develop and publishes from it.

The release pattern is worth reading closely because the packages version independently. The most recent pair is chopper-v8.7.1 and chopper_generator-v8.7.1, both on 2026-10-03, with the generator's previous release 8.7.0 on 2026-07-15. The names carry the package prefix, so a pull request that bumps the runtime will produce a chopper-v tag and one that bumps the generator will produce a chopper_generator-v tag. Two releases with the same numeric suffix are a coordinated pair, not a coincidence.

For an adopter, that means two version numbers to track in build.yaml rather than one. The practical rule is to bump them together, since the generated code produced by one generator version is what the matching runtime version expects.

The repo also lists a skills/ directory at the top level. The listing does not say what it holds, and this article will not guess, but its presence alongside tool/ suggests the project is packaging reusable development guidance or automation alongside the library, which is worth a look before you finalise your own project templates.

## Conclusion

Adopt Chopper when your Dart or Flutter application talks to a typed JSON API and you want request methods, path parameters and response bodies checked at build time rather than by hand, and when you are willing to add a build step to your project. Do not adopt it for a small client with two endpoints, where the generator and its build dependency cost more than the typing saves, and do not assume the package covers everything in the repository, since the generator, the built_value converter and the converters directory are separate pieces with their own versioning. Before you commit, read the LICENSE file, because the repository uses a custom licence that GitHub cannot classify, and check the Getting started document for the exact dependency and build_runner setup.

## FAQ

### What is Chopper and what is it based on?

Chopper is an HTTP client generator for Dart and Flutter using source_gen, inspired by Retrofit. You declare an annotated service class and the build step generates the client implementation.

### How do I install Chopper in a Dart or Flutter project?

The project points at the installation guide on pub.dev and at its Getting started document, and the package is published on pub.dev as chopper. There is no compiled component, since the generation runs through source_gen as part of the Dart build.

### Which packages make up the Chopper project?

The repository holds chopper as the runtime package, chopper_generator as the generator, and chopper_built_value as a separate package for the built_value converter, with further converters under the converters directory. The generator and runtime version independently, with chopper-v8.7.1 and chopper_generator-v8.7.1 both released on 2026-10-03.

### What licence does Chopper use?

The repository is listed under a custom licence that GitHub cannot classify, so the LICENSE file at the repository root is the reference. The project also ships a SECURITY.md for reporting vulnerabilities.

### Does Chopper work with built_value as well as json_serializable?

Yes. The example directory includes main_built_value.dart next to main_json_serializable.dart, and a separate chopper_built_value package carries the built_value flavour of the converter.

## Sources

- [Issues](https://github.com/lejard-h/chopper/issues)
- [lejard-h/chopper on GitHub](https://github.com/lejard-h/chopper)
- [Project website](https://hadrien-lejard.gitbook.io/chopper)
- [README](https://github.com/lejard-h/chopper/blob/develop/README.md)
- [Releases](https://github.com/lejard-h/chopper/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lejard-h-chopper
