Library / SDK
Peternator7/strum avatar
Peternator7/strum

Strum turns enum variants into strings, iterators and constant arrays with derive macros

A small rust library for adding custom derives to enums

2,461 stars195 forksRustMIT

At a glance

What is it?
A small Rust crate for augmenting enums with derived traits, split across a trait crate and a proc-macro crate, with a stated policy of holding its minimum supported Rust version for two years.
Who is it for?
Strum is worth adding when a Rust codebase has an enum that crosses a boundary, because the boilerplate it removes is the kind you write once per project and then copy between projects forever. `EnumString` and `Display` cover the parsing and rendering cases, `EnumIter` covers a picker, and `EnumDiscriminants` covers the case where you want the variant names as a separate type so callers cannot match on the original.
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?
Activity is slowing. The repository last received commits 7 months ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

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

Editorial analysis

Two crates, because traits and macros cannot ship together

The README's installation snippet shows the shape immediately, and it is two dependencies rather than one:

toml
[dependencies]
strum = "0.28"
strum_macros = "0.28"

The reason is explained in the same paragraph: `strum_macros` contains the macros needed to derive all the traits in Strum. A trait and a procedural macro are different kinds of Rust artifact, and keeping them in separate crates means a project that depends only on the traits is not pulling in the macro crate, which matters for compile times in a large dependency graph.

There is also a shorter form. The snippet's commented alternative is the `derive` feature, which lets you import the macros directly from `strum` itself:

toml
strum = { version = "0.28", features = ["derive"] }

The naming has an origin worth knowing, because it explains the API shape. Strum is short for STRing enUM, since the library augments enums with additional information through strings. The README also notes that strumming is a whimsical motion, much like writing Rust code, which tells you the tone of the project as well.

GitHub describes the repository as a small rust library for adding custom derives to enums, with topics for enum and rust-lang. The homepage is the crates.io listing and the licence is MIT.

Twelve derives, grouped by what they generate

The README's table is the API surface, and it sorts into four groups by what actually gets generated.

String conversion is the core: `EnumString` converts strings to enum variants based on their name, `Display` converts variants to strings, `AsRefStr` implements `AsRef<str>` for your enum, and `IntoStaticStr` implements `From<MyEnum> for &'static str`. If you only ever need one of these, it is this group you are after.

Iteration is the second group. `EnumIter` creates a new type that iterates over the variants, and `EnumDiscriminants` generates a new type holding only the discriminant names, which is how you expose the set of possible values without exposing the enum itself. `EnumCount` adds a `usize` constant equal to the number of variants. The last two in this group are the newest-looking: `VariantArray` adds an associated `VARIANTS` constant holding an array of all enum discriminants, and `VariantNames` adds an associated `VARIANTS` constant holding an array of the discriminant names.

Per-variant data is the third group. `EnumProperty` attaches custom properties to variants, `EnumMessage` attaches a verbose message, and `EnumProperty` plus `EnumMessage` together cover the case where a UI needs a label and an identifier per option.

Numeric conversion is `FromRepr`, which converts from an integer to an enum. The practical use is decoding a value that arrived as a raw integer from C, a binary format or a database column.

One detail in that table is worth flagging for anyone counting macros. The link definitions at the bottom of the README include an entry for `EnumIs`, but `EnumIs` has no row in the table itself. So the documentation links a derive the feature list does not describe. Check docs.rs for what it does before relying on the README as a complete index.

Four crates in the workspace, though the README describes three

The contributing section says the project is divided into three parts, and names them: the traits are in the `strum` folder, the procedural macros are in the `strum_macros` folder, and the integration tests are in `strum_tests`. That is a fair description of the architecture and it matches what most users care about.

The repository tree has one more crate in it, though. Alongside `strum/` and `strum_macros/` there are `strum_tests/` and `strum_nostd_tests/`, and the workspace manifest lists all four:

toml
[workspace]
members = [
    "strum",
    "strum_macros",
    "strum_tests",
    "strum_nostd_tests"
]
resolver = "2"

So the README's three-part description is one crate behind the actual layout. The extra crate is a test suite for building without the standard library, which is a meaningful thing to test for a derive crate: if your derives work in a `no_std` build, they cannot be quietly depending on something from `std`. Read the two statements as compatible rather than contradictory, and use the manifest as the accurate list.

Other files in the tree explain the rest of the setup. There is a `.clippy.toml`, an `appveyor.yml` for Windows CI, a `CHANGELOG.md`, and a `.devcontainer/` directory for working on the project in a container. The presence of a clippy configuration alongside a dev container is the profile of a small project that keeps its lint expectations explicit.

STRUM_DEBUG for seeing what the macros actually produce

The debugging section is short and more useful than it has any right to be. Set the `STRUM_DEBUG` environment variable before compiling and the generated code is dumped. `STRUM_DEBUG=1` dumps all of the generated code for every type in the build; `STRUM_DEBUG=YourType` narrows it to one type by name.

bash
STRUM_DEBUG=1

For a library of derives, this matters more than it would for most debugging facilities. When a derive produces something you did not expect, the question is always whether the macro or your attributes are at fault, and the answer is unreadable without seeing the expansion. Scoping the dump to a single type name keeps the output small enough to read, which is the difference between a five-minute answer and a scroll through every type in the dependency tree.

The `1` versus a type name distinction is the part to remember. It is not an on/off switch, it is a filter that accepts either a wildcard or a name, so the useful invocation in practice is the second form.

The contribution guide also sets expectations for anyone adding to the project: bug fixes are welcome directly, but if you want to add a macro you should open an issue first to discuss the feature, because the maintainer says bandwidth for reviewing new features is limited. That is an unusually clear signal about how this project grows.

A two year minimum supported Rust policy, and what the releases show

The compatibility section states that Strum is currently compatible with rustc 1.71.1 and above, that pull requests improving compatibility with older versions are welcome, and that the project goal is to support a Rust version for at least two years after release, with longer preferred, since the project changes slowly.

That is a real policy rather than boilerplate, and it changes how you should read the version number. A derive crate with a fast-moving MSRV forces every downstream user to upgrade Rust on the crate's schedule. One that promises two years means you can take a dependency without becoming the team that blocks everyone else's toolchain upgrade.

The release history supports the slow-change claim. Version 0.28.0 came out on 2026-02-22 and its work is mostly housekeeping: bumping the MSRV to 1.71, using absolute paths in the proc macro, upgrading the `phf` dependency to 0.13, adding missing `#[automatically_derived]` attributes so the compiler stops suggesting the impls are hand-written, fixing existing cargo fmt and clippy issues, and adding GitHub Actions. There are two behavioural changes worth noting: allowing any kind of passthrough attributes on `EnumDiscriminants`, and making `TryFrom` and `FromStr` infallible when the enum has a default variant.

That last one is a design decision you should look at before upgrading. An enum with a default variant can parse any unknown string, because the default absorbs it. That is convenient and it will silently accept typos in your data.

Version 0.27.2 in July 2025 and 0.27.1 in February 2025 are similar in character: doc comment support on the `EnumDiscriminants` type, a `suffix` attribute for serialization of enum variants, a `#[strum(transparent)]` attribute, and dependency upgrades. GitHub reports the last push on 2026-03-07.

Editorial conclusion

Strum is worth adding when a Rust codebase has an enum that crosses a boundary, because the boilerplate it removes is the kind you write once per project and then copy between projects forever. `EnumString` and `Display` cover the parsing and rendering cases, `EnumIter` covers a picker, and `EnumDiscriminants` covers the case where you want the variant names as a separate type so callers cannot match on the original. It is not a serialization framework, and pairing it with one means deciding which of the two owns the wire format. The version to know is 0.28, released on 2026-02-22, with the last push reported on 2026-03-07; the project states a goal of supporting a Rust version for at least two years after release, and adds a macro only after an issue discussion, so read the macro list on docs.rs rather than assuming a feature exists.

Frequently asked questions

What does the Strum crate do in Rust?

It provides macros and traits for augmenting enums with information derived from their variants. That includes converting strings to variants and back, iterating over variants, generating a type of only the variant names, attaching properties or messages to variants, and converting from an integer.

How do I add Strum to a Cargo project?

The README shows adding `strum` and `strum_macros` at version 0.28 to `[dependencies]` in Cargo.toml. The macros live in the separate `strum_macros` crate, so both are needed to derive the traits. There is also a `derive` feature that lets you import the macros directly from `strum` instead.

What is the minimum supported Rust version for Strum?

The README states compatibility with rustc 1.71.1 and above, and release 0.28.0 includes a bump of the MSRV to 1.71. The project states a goal of supporting a Rust version for at least two years after release, and longer where possible, because it changes slowly.

How do I see the code that a Strum derive generates?

Set the `STRUM_DEBUG` environment variable before compiling. `STRUM_DEBUG=1` dumps the generated code for every type, and setting it to a specific type name such as `STRUM_DEBUG=YourType` dumps only that one, which keeps the output readable.

Official sources

  1. License: MIT
  2. Peternator7/strum on GitHub
  3. Project website
  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/peternator7-strum.svg)](https://hysenlabs.com/projects/peternator7-strum)