Library / SDK
ocaml-ppx/ppx_deriving avatar
ocaml-ppx/ppx_deriving

ppx_deriving still generates your show and eq, and the ppx ecosystem has moved on

Type-driven code generation for OCaml

522 stars98 forksOCamlMIT

At a glance

What is it?
ppx_deriving is a library for type-driven code generation in OCaml, with plugins for show, eq, ord, enum, iter, map, fold, make, yojson and protobuf. It is maintained rather than extended, and the documentation says new projects should use ppxlib directly.
Who is it for?
Adopt ppx_deriving if you are maintaining an OCaml codebase that already uses it, since the plugin set is stable and the release line is still moving. Do not adopt it for a new project, because the project's own documentation recommends ppxlib directly for new deriving plugins and describes ppx_deriving as maintained to keep existing plugins working.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 40 days ago.
What is it written in?
Mainly OCaml, according to GitHub's language statistics.

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

Editorial analysis

A derive annotation that generates the functions you would otherwise write

ppx_deriving is described as a library simplifying type-driven code generation on OCaml, and it is a set of useful plugins: show, eq, ord, enum, iter, map, fold, make, yojson and protobuf. The project is sponsored by Evil Martians, the licence is MIT, and the last push was on 2026-09-13, with release 6.2.0 the same day and 6.1.3 and 6.1.2 in the months before.

From a user's perspective, deriving is triggered by a `[@@deriving plugin]` annotation attached to a type declaration in a structure or a signature.

ocaml
type point2d = float * float
[@@deriving show]

That single annotation generates the show function for that type. The generated code follows a naming convention: by default the functions generated by a plugin for a `type foo` are called `fn_foo` or `foo_fn`, but if the type is called `type t`, the function is named `foo`. The defaults can be overridden with an `affix = true|false` plugin option.

Several plugins can be invoked at once by separating their names with commas.

ocaml
type point3d = float * float * float
[@@deriving show, eq]

And a plugin can take options by appending a record to the plugin's name.

ocaml
type t = string
[@@deriving yojson { strict = true }]

The point of all this is that you declare the shape of a value once and the boilerplate for printing it, comparing it, ordering it or serialising it comes out of the type rather than out of your typing.

The deprecation note, and why it is not a deprecation of the plugins

The README carries a note that anyone evaluating this should read before anything else, and it is unusually precise about what it does and does not mean.

Since deriving was released by whitequark in 2014, the OCaml ppx ecosystem has changed a lot. For new projects wishing to create a new deriving plugin, the recommendation is to use ppxlib directly. The module Ppxlib.Deriving provides functionality similar to deriving, better integrated with ppxlib, and offers a nicer API in some places. Deriving is still maintained to keep existing plugins working as well as possible.

And then the last clause, which is the one people misread: the above deprecation note only covers the API and not the plugins, for example ppx_deriving.show, ppx_deriving.eq and the rest.

So the split is this. If you want to write a new deriving plugin, build it on ppxlib. If you want to use the existing plugins, ppx_deriving remains the supported way to do it, and the plugin names and behaviour have not been deprecated.

That distinction matters for an adopter, because the phrase deprecating ppx_deriving is a summary people repeat without the qualifier. A codebase that uses `[@@deriving show, eq]` is not being asked to migrate. A person who wants to write their own deriving plugin is.

The practical consequence is a fork in the road at the start of a project, and the project has already chosen both branches for you.

Build integration is the part that trips people up

To use deriving, only one modification is needed: you need to require via ocamlfind the package corresponding to the deriving plugin. This will both engage the syntax extension and link in the runtime components of the plugin, if any.

That single requirement is the whole integration contract, and it is expressed differently by each build system.

For ocamlbuild, you add a line to `_tags` to use the default deriving plugins.

code
<src/*>: package(ppx_deriving.std)

With Dune, you add a `preprocess` directive to your target.

code
(executable
  (libraries whatever)
  (preprocess (pps ppx_deriving.show ppx_deriving.ord))
  (name blah))

And if you are using another buildsystem, you just make sure it passes `-package ppx_deriving.whatever` to ocamlfind.

The Dune form is worth understanding rather than copying. The `pps` directive links the named preprocessors into a single executable, which the documentation says allows faster preprocessing and can significantly speed up compilation on large projects which use many derivers. So the names you list in the Dune directive are not decorative: they are the plugins being compiled into one preprocessor binary, and the choice of list is also a performance decision.

If you forget the requirement, the symptom is a build error rather than a silently missing function, which is the friendly outcome. But the list of plugins must match what your annotations actually use, since each `[@@deriving ...]` needs its plugin present.

Deriving for types you did not declare, which is the lesser-known part

At first it may look like deriving requires complete control of the type declaration. However, a lesser-known OCaml feature allows to derive functions for any existing type.

The example given uses `Stdlib.fpclass`, and derives show for it by re-declaring the type in a module as a type equation.

ocaml
# module M = struct
  type myfpclass = fpclass = FP_normal | FP_subnormal | FP_zero | FP_infinite | FP_nan
  [@@deriving show]
end;;

The module is used to demonstrate that `show_myfpclass` really accepts `Stdlib.fpclass`, and not just `M.myfpclass`. That is the point of the example, and it is a real constraint rather than a formality. The type equation is what ties the derived function to the original type, and if you get the equation wrong you get a function over a different type that happens to have the same shape.

To avoid the need to repeat the type definition, it is possible to use ppx_import to automatically pull in the type definition, with attributes attached using its `[@with]` replacement feature.

There is a related trick for using a deriver without declaring the type first. The `[%derive.x:]` syntax can derive a function directly from a type, without declaring it first.

ocaml
let sort = List.sort [%derive.ord: int * int] in

And the syntax can be shortened to `[%x:]`, given that the deriver `x` exists and the payload is a type. If those conditions are not satisfied, the extension node is left uninterpreted, to minimize potential conflicts with other rewriters.

That last fallback is a nice piece of design. Rather than erroring on an ambiguous extension node, the rewriter declines to touch it, which means two independent rewriters can both be present in a compilation without fighting over the same node.

The plugin conventions, which are the real API

The documentation devotes a section to plugin conventions, and it is the closest thing the project has to a specification for anyone writing or using a deriving plugin.

The naming convention is the first rule. By default the functions generated by a plugin for a `type foo` are called `fn_foo` or `foo_fn`, and if the type is called `type t` the function is named `foo`, overridable with the `affix` option.

The second rule is about attributes and namespaces, and it is the subtle one. In the case of a plugin named `eq` and attributes named `compare` and `skip`, the plugin must recognize all of `compare`, `skip`, `eq.compare`, `eq.skip`, `deriving.eq.compare` and `deriving.eq.skip` annotations. However, if it detects that at least one namespaced attribute is present, it must not look at any attributes located within a different namespace. The result is that different ppx rewriters can avoid interference even if the attribute names they use overlap.

That is a genuinely good design decision and it explains why deriving survived the ecosystem change. Namespace-qualified attributes let two libraries claim the same short attribute name, and the rule that a namespaced attribute shadows all unqualified ones means a plugin never guesses.

The third rule is what a plugin has to handle. A typical plugin should handle tuples, records, normal and polymorphic variants, the builtin types including `int`, `int32`, `int64`, `nativeint`, `float`, `bool`, `char`, `string`, `bytes`, `ref`, `list`, `array`, `option`, `lazy_t` and their `Mod.t` aliases, `Result.result` available since 4.03 or in the `result` opam package, abstract types and `_`. For builtin types the default behaviour should be customizable and sensible, and it should not be used if a type has a `[@nobuiltin]` attribute attached to it, in which case the type is treated as abstract. For abstract types the plugin should expect to find the functions it would derive itself for that type.

The last rule is about parametric types: if a type is parametric, the generated functions accept an argument for every type variable before all other arguments.

Where ppx_deriving is the wrong choice

Three cases, and the project has already decided the first one for you.

If you are starting a new project and intend to write any deriving plugin of your own, use ppxlib directly. The documentation says so directly, and the reason given is that the module provides similar functionality, better integrated with ppxlib, and offers a nicer API in some places. Deriving exists here for compatibility, not as the recommended base for new work.

The second is if you only need one function and want no build system coupling. The install path requires wiring a package requirement into your build system, and with Dune that means listing the plugins in a preprocess directive. A single `show` function for one debug print is a lot of machinery, and writing it by hand is often shorter than the integration.

The third is if the type does not fit the derivation model. The plugin conventions expect a type to be a tuple, record, variant, a listed builtin, or abstract with the relevant functions already present. A type with an unusual internal shape, or one where the default builtin behaviour is wrong, needs a `[@nobuiltin]` attribute and the plugin's own functions, which means writing the functions anyway and only getting the plumbing for free.

There is also a version-practical point. The plugin names are stable and the release line is moving, at 6.2.0 in September 2026, but the ppx ecosystem underneath it has moved to ppxlib. A project that is already on ppxlib and wants to add deriving to an existing codebase can reasonably evaluate ppxlib.Deriving instead, and the documentation suggests exactly that comparison.

Editorial conclusion

Adopt ppx_deriving if you are maintaining an OCaml codebase that already uses it, since the plugin set is stable and the release line is still moving. Do not adopt it for a new project, because the project's own documentation recommends ppxlib directly for new deriving plugins and describes ppx_deriving as maintained to keep existing plugins working. Verify first which plugins your build actually links, because with Dune the pps directive names them explicitly and a missing plugin is a compile error rather than a missing function.

Frequently asked questions

What is ppx_deriving?

It is a library simplifying type-driven code generation on OCaml, shipped as a set of plugins: show, eq, ord, enum, iter, map, fold, make, yojson and protobuf. It is licensed MIT and sponsored by Evil Martians.

Is ppx_deriving deprecated?

The deprecation note covers the API for creating new deriving plugins, not the existing plugins. For new deriving plugins the project recommends using ppxlib directly, while deriving is still maintained to keep existing plugins working as well as possible.

How do I install ppx_deriving?

Through OPAM with opam install ppx_deriving. To use it in a build you also need to require the package for the specific plugin via ocamlfind, for example adding a package(ppx_deriving.std) line to _tags with ocamlbuild or a preprocess (pps ...) directive with Dune.

Can ppx_deriving generate code for a type I did not declare?

Yes. A lesser-known OCaml feature allows deriving functions for any existing type, as the Stdlib.fpclass example demonstrates with a type equation. ppx_import can also pull in the type definition automatically, and the [%derive.x:] syntax derives a function directly from a type without declaring it first.

What naming convention do the generated functions follow?

By default the functions generated by a plugin for a type foo are called fn_foo or foo_fn, and if the type is called type t the function is named foo. The defaults can be overridden with the affix = true|false plugin option.

Official sources

  1. Issues
  2. License: MIT
  3. ocaml-ppx/ppx_deriving 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/ocaml-ppx-ppx-deriving.svg)](https://hysenlabs.com/projects/ocaml-ppx-ppx-deriving)

Was this useful?