Skip to content

Instantly share code, notes, and snippets.

@mre
Created May 16, 2025 23:08
Show Gist options
  • Save mre/bd72da1b85d1429f38dc39fe4de9324b to your computer and use it in GitHub Desktop.
Save mre/bd72da1b85d1429f38dc39fe4de9324b to your computer and use it in GitHub Desktop.
Are Type Crates an Antipattern?

Why you think it's an anti-pattern to have a "types" crate?

Discussion at: https://fosstodon.org/@ianthetechie/114517520321760826

That's a fair question. What I found is that "types" is a bit of a scapegoat for things that have a proper place yet, similar to "utils", "shared." The types crate tends to become a dumping ground for types that don't have a fixed place yet. Code in those crates is not really "discoverable" as in: I would have to look into the crate to see what's in there and how it relates to the rest of the codebase.

For example, the standard library has a bunch of primitive types, but they all live in their own module in the core crate. The rest lives close to the supporting code, e.g. see the structs in std::process (https://doc.rust-lang.org/std/process/index.html#structs). If these structs were all in the types crate, it would make the code and the documentation a lot harder to navigate in my opinion.

The other problem with type crates is that supporting code either lives in a separate crate, which causes a weird context switches or it's in the types crate as well and blows up its size as more functionality is added. I find that the latter often makes it hard to separate concerns in the long run. For example, say I wanted to provide a stable API for some (not all!) of my types and I wanted to expose them as a library. Then I would need to move that code to a separate crate instead of just pushing that crate to crates.io.

I found that types are mostly unrelated. Initially, it's convenient to put them all into the same crate, but over time it makes it harder to have clear bounded contexts between the different domains. In comparison, by moving types and their supporting code into their own module, we get a natural separation of concerns and achieve loose coupling and high cohesion. (https://en.wikipedia.org/wiki/Coupling_(computer_programming))

I'm not without sin here. E.g. in lychee, we still have a types crate and I'm not happy about that. https://github.com/lycheeverse/lychee/tree/master/lychee-lib/src/types We need to move those types out at some point. For new projects, I tend to move types closer to where they get used.

There's probably more to it and I could expand on it in a longer-form text if you like.

I also want to say that I don't feel too hard about all of the above and that there are good use-cases for types crates as well, e.g. if you build a math library and you want to expose all the primitives from one place; but that's rare for the work that I do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment