Kittens: automatic type class derivation for Cats on Scala 2 and Scala 3
Automatic type class derivation for Cats
At a glance
- What is it?
- Kittens is a Typelevel library that derives Cats type class instances for arbitrary algebraic data types, using shapeless-based derivation on Scala 2 and the language's own derivation on Scala 3. It also ships utility functions for lifting, traversing and sequencing over HLists, Records and case classes, and the same artefact works on the JVM, Scala.js and Scala Native.
- Who is it for?
- Kittens suits a Scala team using Cats who has a lot of small case classes and does not want to hand-write an Eq or a Show for each one, since semiauto derivation gives you one line per type while respecting existing instances in scope. It does not suit a Scala 3 codebase that has already adopted the language's own derives clauses, and it does not suit a library author who needs guaranteed instance uniqueness, which the cached derivation warns about explicitly.
- Can I use it commercially?
- Yes. Apache-2.0 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 6 days ago.
- What is it written in?
- Mainly Scala, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Derivation for ADTs, with the type class list spelled out
Kittens is a Scala library which provides instances of type classes from the Cats library for arbitrary algebraic data types using Shapeless-based automatic type class derivation. It also provides utility functions related to Applicative such as lift, traverse and sequence to HList, Record and case classes.
So there are two halves to the library, and they are related. The type class instances are the headline feature, and the utility functions are the reason the type classes are worth deriving in the first place.
The Scala 2 instance list is long and specific, and it is worth reading to know what is covered.
- `Eq`, `PartialOrder`, `Order`, `Hash` - `Show`, pretty `Show` - `Empty`, `EmptyK` (from Alleycats) - `Semigroup`, `CommutativeSemigroup`, `SemigroupK` - `Monoid`, `CommutativeMonoid`, `MonoidK` - `Functor`, `Contravariant`, `Invariant` - `Pure` (from Alleycats), `Apply`, `Applicative` - `Foldable`, `Reducible` - `Traverse`, `NonEmptyTraverse` - `ConsK` (from Alleycats)
Note which ones come from Alleycats rather than Cats: Empty, EmptyK, Pure and ConsK. So the effective dependency surface is Cats plus Alleycats, which is worth knowing if you are counting dependencies.
A derivation is a one line import of a companion object.
scala> import cats.implicits._, cats._, cats.derived._
scala> case class Cat[Food](food: Food, foods: List[Food])
defined class Cat
scala> val cat = Cat(1, List(2, 3))
cat: Cat[Int] = Cat(1,List(2, 3))And then the instance is asked for by name.
scala> implicit val fc: Functor[Cat] = semiauto.functor
FC: cats.Functor[Cat] = cats.derived.MkFunctor2$$anon$4@1c60573f
scala> cat.map(_ + 1)
res0: Cat[Int] = Cat(2,List(3, 4))So `semiauto.functor` is a value of type Functor[Cat], assigned to an implicit val, and from then on the standard Cats syntax works.
The primary language is Scala, the licence is Apache-2.0 with a LICENSE file and a CONTRIBUTORS file at the root, and the last push was on 2026-10-17. The release history is v3.5.0 from 2025-03-04, v3.4.0 from 2024-08-21 and v3.3.0 from 2024-03-08.
Existing instances in scope are respected, and that is the point
The Show example in the README is the one that explains why semiauto is the recommended derivation mode, and it is worth following.
The setup is a nested structure, with an Address inside a ContactInfo inside a People.
scala> case class Address(street: String, city: String, state: String)
scala> case class ContactInfo(phoneNumber: String, address: Address)
scala> case class People(name: String, contactInfo: ContactInfo)
scala> val mike = People("Mike", ContactInfo("202-295-3928", Address("1 Main ST", "Chicago", "IL")))
scala> // existing Show instance for Address
scala> implicit val addressShow: Show[Address] =
a => s"${a.street}, ${a.city}, ${a.state}"
scala> implicit val peopleShow: Show[People] = semiauto.show // auto derive Show for PeopleThe comment calls out the existing instance, and the README then states what happened. The derivation generated instances for all referenced classes but still respected the existing instance in scope.
That is the behaviour that makes the library safe to use in a codebase with hand-written instances. If you wrote a custom Show for Address, the derived Show for People uses it for the nested field rather than generating a competing one.
The output is also different from the default toString, and the README notes that the derived Show also prints out field names, so it might be preferable to the default toString.
scala> mike.show
res0: String = People(name = Mike, contactInfo = ContactInfo(phoneNumber = 202-295-3928, address = 1 Main ST, Chicago, IL))And there is a worked example of the composition. Show[List[A]] will use the native Show instance for List and derived instance for A.
So derivation is not a replacement for your hand-written instances. It fills the gaps around them, which is a different promise from the auto derivation mode that derives everything from scratch.
Three derivation modes on Scala 2, with a real trade-off in each
The Scala 2 section says there are three options for type class derivation, cats.derived.auto, cats.derived.cached and cats.derived.semiauto, and that the recommended best practice is to use semiauto.
import cats.derived
implicit val showFoo: Show[Foo] = derived.semiauto.showThe three modes differ in where the instance lives and when it is computed.
Auto derivation is a wildcard import.
import derived.auto.show._The downside is that it will derive an instance from scratch for every use site, increasing compilation time. That is a real cost in a large codebase, because derivation is not cheap and doing it per use site multiplies the work.
Cached derivation is the other wildcard import.
import derived.cached.show._And the README tells you to use this one with caution, because it caches the derived instance globally. So it's only applicable if the instance is global in the application, and this could be problematic for libraries, which have no control over the uniqueness of an instance at use site.
That is an unusually direct statement of a hazard. In a library, your code is compiled into someone else's application, and if the application also has a cached instance for the same type, there is a conflict the library author cannot prevent.
Semiauto is the one line per type.
implicit val showFoo: Show[Foo] = derived.semiauto.showThe downside here is that we need to write one for every type that needs an instance.
So the trade is explicit compilation time against explicit lines. Auto is fast to write and slow to compile, cached is fast to compile and dangerous to publish, semiauto is one line per type and safe.
That framing is the reason semiauto is the recommendation. It puts the decision at the point where you know whether the instance should be global, and it makes the instance visible in the source rather than implicit.
Scala 3 gets a different set of options, and a strict mode
The Scala 3 section is short in the visible README, but it lists the differences from Scala 2 and they are the ones that matter for a migration.
There are five options for type class derivation on Scala 3, and the recommended way is to import cats.derived.* and use derives clauses.
import cats.derived
implicit val showFoo: Show[Foo] = derived.semiauto.showThe three differences in contrast to Scala 2 are the important part.
Cached derivation is not supported, and also not necessary. That removes the hazard the Scala 2 section warns about, because there is no global cache to conflict over.
Type Class Derivation is supported, which is the Scala 3 language feature for deriving instances given a given instance in scope, rather than through a separate derivation mechanism.
A strict mode is available for semiauto and derives clauses.
Strict mode is worth understanding, because it is not in the Scala 2 story at all. In a non-strict derivation, the compiler will fall back to a generic derivation if it cannot find a specific instance for a field, which means a typo in a type name can silently produce a less precise instance rather than an error. Strict mode removes that fallback, so a missing instance becomes a compile error.
For a team moving from Scala 2 to Scala 3, that is the headline difference. The Scala 2 semiauto behaviour of respecting existing instances in scope has an equivalent in Scala 3, and the strict mode gives it teeth.
The cross platform support is unchanged. It is available for Scala 2.12 and 2.13, Scala.js 1.5 and Scala Native 0.4, which is the usual Typelevel range and means the same artefact works for a JVM service, a Scala.js front end and a Native build.
lift, traverse and sequence are the utility half of the library
The utility functions are what turn derived instances into something you actually use, and they are documented with their own examples.
The lift example is the shortest.
scala> import cats._, implicits._, lift._
import cats._
import implicits._
import lift._
scala> def foo(x: Int, y: String, z: Float) = s"$x - $y - $z"
scala> val lifted = Applicative[Option].liftA(foo _)So lift turns a three argument function into a function of three Options producing an Option, which is the usual applicative lifting but written against the derived instances.
The sequence examples are the more involved ones, and they need a compiler flag. To run these examples, you need partial unification enabled, and for Scala 2.12 you should add the following to your build.sbt.
scalacOptions += "-Ypartial-unification"The example then sequences three functions into an HList.
scala> val f = sequence(f1, f2, f3)
f: String => shapeless.::[Int,shapeless.::[String,shapeless.::[Float,shapeless.HNil]]] = <function1>
scala> f("42.0")
res0: shapeless.::[Int,shapeless.::[String,shapeless.::[Float,shapeless.HNil]]] = 4 :: 0.24 :: 42.0 :: HNilAnd the same thing generically over an ADT.
scala> val myGen = sequenceGeneric[MyCase]
myGen: cats.sequence.sequenceGen[MyCase] = cats.sequence.SequenceOps$sequenceGen@63ae3243
scala> val f = myGen(a = f1, b = f2, c = f3)
f: String => MyCase = <function1>
scala> f("42.0")
res1: MyCase = MyCase(4,0.24,42.0)Traverse works similarly except you need a shapeless.Poly.
The generic version is the interesting one. sequenceGeneric produces a sequence function for any case class, so you do not need to hand-write the Applicative for your type, which is the point of having derivation at all.
Where Kittens is the wrong tool
The first wrong-tool case is a Scala 3 codebase that has adopted the language's own derivation. If you are on Scala 3, the README's recommended path is imports of cats.derived.* with derives clauses, and the built-in Type Class Derivation is supported. Kittens on Scala 3 is essentially a thin layer over what the compiler does, so the value of the library on Scala 3 is smaller, though the semiauto and strict modes still save you writing one val per type.
The second case is a library author. The cached derivation section says it directly: this could be problematic for libraries, which have no control over the uniqueness of an instance at use site. If you publish a library, you cannot use cached derivation, and if you rely on auto derivation you accept a compile time cost that your users pay.
The third case is a project that has no Cats. Everything here is about deriving instances of Cats type classes, and the utility functions are built around Applicative. If your algebra is not Cats, this library does nothing for you, and the shapeless dependency on Scala 2 is a heavy one to pull in for nothing.
The fourth case is a large data model with heavy instances. Derivation works by inspecting the structure of your type, and the cost grows with the depth and breadth of that structure. The README does not document how derivation scales for a deeply nested ADT, and the auto mode's compile time cost is called out as a downside without a figure. A codebase with hundreds of case classes and auto derivation is a compile time risk.
There is also a version compatibility constraint to note. It is available for Scala 2.12 and 2.13, Scala.js 1.5 and Scala Native 0.4, so a project on Scala 3.3 with an older Scala.js is outside the range, and on Scala 2.12 the sequence examples additionally need partial unification enabled.
The dependency story is worth knowing too. The Scala 2 derivation is Shapeless-based, and the Shapeless library has been in maintenance mode for years, so the Scala 2 path of Kittens sits on a foundation that is unlikely to gain features.
On licence, Apache-2.0 with a LICENSE file at the root, and binary artifacts are published to the Sonatype OSS Repository Hosting service and synced to Maven Central, so there is no question about where the artefact comes from. The project is part of the Typelevel family, which is a community of Scala libraries with a shared style and a shared release process, and the build.sbt, project/ and core/ directories at the root are a conventional sbt layout. The repository also carries a .scala-steward.conf file, which is how the project tracks upstream dependency bumps.
Editorial conclusion
Kittens suits a Scala team using Cats who has a lot of small case classes and does not want to hand-write an Eq or a Show for each one, since semiauto derivation gives you one line per type while respecting existing instances in scope. It does not suit a Scala 3 codebase that has already adopted the language's own derives clauses, and it does not suit a library author who needs guaranteed instance uniqueness, which the cached derivation warns about explicitly. Before adopting, check the type class support matrix in the README for the instances you actually need, since some of them come from Alleycats rather than Cats, and note that on Scala 2 you will need -Ypartial-unification for the sequence examples.
Frequently asked questions
What is Typelevel Kittens?
Kittens is a Scala library that provides instances of Cats type classes for arbitrary algebraic data types using Shapeless-based automatic derivation on Scala 2. It also provides utility functions related to Applicative such as lift, traverse and sequence to HList, Record and case classes.
How do I add Kittens to an sbt build?
Add libraryDependencies += "org.typelevel" %% "kittens" % "latestVersion" to your build.sbt file, with the version indicated in the badge. Binary artefacts are published to Sonatype OSS Repository Hosting and synced to Maven Central.
Which derivation mode should I use in Kittens on Scala 2?
The README recommends semiauto, written as implicit val showFoo: Show[Foo] = derived.semiauto.show, because it respects existing instances in scope and caches the result manually. Auto derivation recompiles an instance per use site and slows compilation, and cached derivation caches globally, which the README warns is problematic for libraries.
What changes between Kittens on Scala 2 and Scala 3?
On Scala 3 the README recommends importing cats.derived.* and using derives clauses, cached derivation is not supported and is not necessary, the Scala 3 Type Class Derivation feature is supported, and a strict mode is available for semiauto and derives clauses.
Which type class instances can Kittens derive?
Eq, PartialOrder, Order, Hash, Show, pretty Show, Empty, EmptyK, Semigroup, CommutativeSemigroup, SemigroupK, Monoid, CommutativeMonoid, MonoidK, Functor, Contravariant, Invariant, Pure, Apply, Applicative, Foldable, Reducible, Traverse, NonEmptyTraverse and ConsK. Empty, EmptyK, Pure and ConsK come from Alleycats rather than Cats.
What license is Kittens released under?
Kittens is an Open Source project under the Apache License v2, with the LICENSE file at the root of the repository. It is part of the Typelevel family of projects, is available for Scala 2.12 and 2.13, Scala.js 1.5 and Scala Native 0.4, and the current release is v3.5.0.
Official sources
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.
[](https://hysenlabs.com/projects/typelevel-kittens)Was this useful?