PackageTrack
Sign in Get early access

nutype

The newtype with guarantees.

0.7.0 5.4M downloads/mo #4371 most downloaded on crates.io greyblake/nutype

What this package is like to depend on

Last release 2 months ago

18 Jun 2026

Release timing varies

gaps range from 8 days to 9 months

Nearly every release is documented

notes for 14 of 15 stable releases

Nothing withdrawn

no release was ever pulled

4 years old

22 releases · first in 2022

2 releases in the last 12 months

see the full history below

Release timeline

22 releases · Oct 2022 to Jun 2026
2023 2024 2025 2026
Release Pre-release

Releases

latest 22
  1. 0.8.0-beta.1 18 Jun 2026 pre-release

    Nothing published for this version

  2. 0.7.0 25 Apr 2026
    Release notes

    What is nutype?

    Nutype is a Rust proc macro for type-driven domain modeling: it turns the newtype pattern into refined, branded types with built-in sanitizers (trim, lowercase, custom) and validators (length, range, regex, predicates, custom errors). It's "parse, don't validate" applied to your domain, useful for DDD, schema validation at API boundaries, and making illegal states unrepresentable, even across serde, FromStr, and arbitrary fuzzing.

    Changes in v0.7.0

    • [BREAKING] Renamed derive_unsafe to derive_unchecked (both the feature flag and the attribute).
    • [FEATURE] Support cfg_attr for conditional derives (see #188).
    • [FEATURE] Support where clauses in generic newtypes, including Higher-Ranked Trait Bounds (HRTB) (see #160).
    • [FEATURE] Ability to control constructor visibility with the constructor(visibility = ...) attribute (see #211).
    • [FEATURE] Add len_utf16_min and len_utf16_max validators for string types (see #162).
    • [FEATURE] Ability to derive Valuable (requires the valuable feature).

    Conditional derives via cfg_attr

    A long-standing request (#188): derive traits only when a feature is enabled, only in tests, or under any other cfg predicate.

    In v0.7.0 you can now write cfg_attr(...) directly inside #[nutype(...)], mirroring the standard #[cfg_attr] syntax:

    use nutype::nutype;
    
    #[nutype(
        sanitize(trim, lowercase),
        validate(not_empty, len_char_max = 100),
        derive(Debug, Clone, PartialEq, AsRef),
        cfg_attr(feature = "serde", derive(Serialize, Deserialize))
    )]
    pub struct Email(String);

    Here Serialize and Deserialize are only derived when the serde feature is active. Note: nutype/serde must still be enabled at compile time so the macro recognizes those traits, but the actual derive is gated by cfg_attr.

    You can use any predicate the standard cfg_attr accepts, including all(...), any(...), and not(...), and you can stack multiple cfg_attr(..) entries:

    #[nutype(
        validate(not_empty),
        derive(Debug),
        cfg_attr(test, derive(Clone)),
        cfg_attr(feature = "serde", derive(Serialize, Deserialize))
    )]
    pub struct Tag(String);

    A complete walkthrough lives in examples/cfg_attr_example.

    where clauses and HRTB for generic newtypes

    Generic newtypes now accept full where clauses, including Higher-Ranked Trait Bounds (#160):

    use nutype::nutype;
    
    #[nutype(
        validate(predicate = |c| c.into_iter().next().is_some()),
        derive(Debug)
    )]
    struct NonEmpty<C>(C)
    where
        for<'a> &'a C: IntoIterator;
    
    let xs = NonEmpty::try_new(vec![1, 2, 3]).unwrap();

    Inline bounds and where clauses can also be combined:

    #[nutype(derive(Debug, Clone))]
    struct Combined<T: Clone>(T)
    where
        T: Default;

    Constructor visibility

    Until now, ::new() / ::try_new() were always pub. In v0.7.0 you can pin the constructor to any visibility you like via constructor(visibility = ...) (#211):

    use nutype::nutype;
    
    #[nutype(
        constructor(visibility = pub(crate)),
        validate(not_empty),
        derive(Debug, AsRef),
    )]
    pub struct InternalId(String);

    Supported values are pub, pub(crate), pub(super), pub(in path), and private. With private, the constructor is only callable from the module where the type is defined, useful for types that should only be obtained through a higher-level factory.

    UTF-16 length validators

    JavaScript and a few other ecosystems count string length in UTF-16 code units rather than Unicode characters or bytes. To make interop straightforward, v0.7.0 adds len_utf16_min and len_utf16_max (#162):

    use nutype::nutype;
    
    #[nutype(
        validate(len_utf16_min = 1, len_utf16_max = 280),
        derive(Debug, AsRef),
    )]
    pub struct Tweet(String);

    These complement the existing len_char_min / len_char_max (Unicode chars) validators.

    Deriving Valuable

    When the valuable feature is enabled, you can now derive Valuable on your newtypes, useful for structured logging with tracing and similar instrumentation:

    use nutype::nutype;
    use valuable::Valuable;
    
    #[nutype(derive(Valuable))]
    pub struct Age(u32);
    
    #[nutype(derive(Valuable))]
    pub struct Name(String);
    
    assert_eq!(format!("{:?}", Age::new(25).as_value()), "Age(25)");

    Add it to your Cargo.toml as:

    nutype = { version = "0.7", features = ["valuable"] }
    valuable = { version = "0.1", features = ["derive"] }

    Links

    Open source →
    Release notes
    • [BREAKING] Rename derive_unsafe to derive_unchecked (both the feature flag and the attribute).
    • [FEATURE] Support cfg_attr for conditional derives, e.g. cfg_attr(feature = "serde", derive(Serialize, Deserialize)). Supports complex predicates and multiple entries.
    • [FEATURE] Support where clauses in generic newtypes, including Higher-Ranked Trait Bounds (HRTB) like for<'a> &'a C: IntoIterator (see #160).
    • [FEATURE] Ability to control constructor visibility with constructor(visibility = ...) attribute (see #211).
    • [FEATURE] Add len_utf16_min and len_utf16_max validators for string types to validate UTF-16 code unit length (useful for JavaScript interop) (see #162).
    • [FEATURE] Ability to derive Valuable (requires valuable feature).
    Open source →
  3. 0.6.2 30 Jul 2025
    Release notes

    What is nutype?

    Nutype is a proc macro that adds sanitization_ and validation to newtypes, ensuring values always pass checks.

    Changes in v0.6.2

    • [FEATURE] Introduce derive_unsafe(..) attribute to derive any arbitrary trait (requires derive_unsafe feature to be enabled).
    • [FIX] Updated the Rust edition: 2021 → 2024.
    • [FIX] Improved error messages for len_char_max and len_char_min validators. They are now clearer and easier to understand.

    derive_unsafe

    You can now use the new derive_unsafe(..) attribute to derive arbitrary traits, including third-party ones, which are not known to nutype.

    Unlike derive(..), this mechanism bypasses nutype’s internal safety checks, meaning it's possible to violate validation rules at runtime if you're deriving a trait that has methods that instantiate or mutate a value.

    It requires derive_unsafe feature flag to be enabled.

    Example (do not copy blindly):

    use derive_more::{Deref, DerefMut};
    use nutype::nutype;
    
    #[nutype(
        derive(Debug, AsRef),
        derive_unsafe(Deref, DerefMut),
        validate(greater_or_equal = 0.0, less_or_equal = 2.0)
    )]
    struct LlmTemperature(f64);
    
    fn main() {
        let mut temperature = LlmTemperature::try_new(1.5).unwrap();
    
        // This is not what nutype is designed for!
        *temperature = 2.5;
    
        // OH no, we've just violated the validation rule!
        assert_eq!(temperature.as_ref(), &2.5);
    }

    The takeaway: derive_unsafe gives you raw power—but you’re on your own to ensure your type’s invariants aren't broken.

    On that note, have a nice day!.

    Open source →
    Release notes
    • [FEATURE] Introduce derive_unsafe(..) attribute to derive any arbitrary trait (requires derive_unsafe feature to be enabled).
    • [FIX] Update Rust edition: 2021 -> 2024.
    • [FIX] Improve error messages for len_char_max and len_char_min validators.
    Open source →
  4. 0.6.1 09 Feb 2025
    Release notes

    Changes

    • Fix derive(Deserialize) for no_std (see #207)
    Open source →
    Release notes
    • [FIX] Fix derive(Deserialize) for no_std.
    Open source →
  5. 0.6.0 02 Feb 2025
    Release notes

    What is nutype?

    Nutype is a proc macro that adds sanitizatio_ and validation to newtypes, ensuring values always pass checks, even with serde deserialization.

    Changes in v0.6.0

    • [FEATURE] You can now instantiate types in a const context if they are declared with the const_fn flag.
    • [FEATURE] You can now derive IntoIterator for types wrapping inner types that implement IntoIterator.
    • [FIX] &'a str is now supported as an inner type.
    • [BREAKING] The fallible ::new() constructor has been removed (it was deprecated in 0.4.3).

    Const functions

    The #[nutype] macro can now accept the const_fn flag, which instructs it to generate const fn new() / const fn try_new() functions. This allows you to create instances in a const context:

    use nutype::nutype;
    
    #[nutype(
        const_fn,
        validate(greater_or_equal = -1.0, less_or_equal = 1.0)
    )]
    struct Correlation(f64);
    
    // Since Result::unwrap() is not yet supported in a const context, we need to handle the result manually:
    const ZERO_CORRELATION: Correlation = match Correlation::try_new(0.0) {
        Ok(c) => c,
        Err(_) => panic!("Invalid Correlation value"),
    };

    Because manually unwrapping in a const context can be tedious, you can use a helper macro like the one below (not part of nutype):

    macro_rules! nutype_const {
        ($name:ident, $ty:ty, $value:expr) => {
            const $name: $ty = match <$ty>::try_new($value) {
                Ok(value) => value,
                Err(_) => panic!("Invalid value"),
            };
        };
    }
    
    nutype_const!(ZERO_CORRELATION, Correlation, 0.0);

    IntoIterator

    Types that wrap a collection can now derive IntoIterator. This automatically provides both a consuming iterator (impl IntoIterator for T) and an iterator over references (impl IntoIterator for &T).

    Example:

    use nutype::nutype;
    
    #[nutype(derive(IntoIterator))]
    struct Names(Vec<String>);
    
    fn main() {
        let names = Names::new(vec![
            "Alice".to_string(),
            "Bob".to_string(),
        ]);
    
        // Iterate over references
        for name in &names {
            println!("{}", name);
        }
    
        // Iterate over owned values (consuming iterator)
        for name in names {
            println!("{}", name);
        }
    }
    Open source →
    Release notes
    • [FEATURE] Ability to instantiate types in const context, when declared with const_fn flag.
    • [FEATURE] Support derive(IntoIterator) for inner types that implement IntoIterator.
    • [FIX] Enable &'a str as an inner type.
    • [BREAKING] Fallible ::new() constructor is removed (was deprecated in 0.4.3).
    Open source →
  6. 0.5.1 20 Dec 2024
    Release notes

    I am excited to announce the release of Nutype 0.5.1, which brings some fixes for an improved developer experience. Below is an overview of what's included in this version:

    🚀 New Features

    • no_std Support for ::core::error::Error
      Nutype now generates an implementation of ::core::error::Error in no_std environments when using Rust version 1.81 or higher. This enhancement ensures better compatibility with modern Rust ecosystems.

    🛠️ Bug Fixes

    • Custom Error Paths
      You can now specify custom errors using a path, providing greater flexibility for your error-handling needs.
      (#186, #187)

    • Deserialize Derive Compatibility
      Resolved an issue where deriving Deserialize caused compilation errors when using both no_std and serde features.
      (#182)

    • Lint Warnings
      Fixed unnecessary lint warnings related to the inner generated module for cleaner builds.

    • Conflict with borsch Crate
      Addressed a conflict with the borsch crate to ensure seamless integration.
      (#195)

    Open source →
    Release notes
    • [FEATURE] In no_std generate implementation of ::core::error::Error if Rust version is 1.81 or higher.
    • [FIX] Enable to specify custom error as a path (see #186, #187)
    • [FIX] Make Deserialize derive compile when combination of no_std and serde features are used (#182)
    • [FIX] Fix lint warnings about inner generated module
    • [FIX] Fix a conflict when used with borsch crate (#195)
    Open source →
  7. 0.5.0 02 Sep 2024
    Release notes

    Changes

    • [FEATURE] Added support for custom error types and validation functions via the error and with attributes.
    • [BREAKING] Replaced lazy_static with std::sync::LazyLock for regex validation. This requires Rust 1.80 or higher and may cause compilation issues on older Rust versions due to the use of std::sync::LazyLock. If upgrading Rust isn't an option, you can still use lazy_static explicitly as a workaround.
    • [BREAKING] The fallible ::new() constructor has been fully replaced by ::try_new().

    Highlights

    Custom errors

    Previously, custom validation logic in nutype could be achieved by passing a predicate attribute, as shown below:

    #[nutype(validate(predicate = |n| n % 2 == 1))]
    struct OddNumber(i64);

    This would automatically generate a simple error type:

    enum OddNumberError {
        PredicateViolated,
    }

    However, this approach often lacked flexibility. Many users needed more detailed error handling. For example, some users wanted to attach additional information to errors or provide more descriptive error messages. Others preferred to use a single error type across their application, but found it cumbersome to map very specific errors to a more general error type.

    To address these needs, nutype now introduces the with attribute for custom validation functions and the error attribute for specifying custom error types:

    use nutype::nutype;
    
    // Define a newtype `Name` with custom validation logic and a custom error type `NameError`.
    // If validation fails, `Name` cannot be instantiated.
    #[nutype(
        validate(with = validate_name, error = NameError),
        derive(Debug, AsRef, PartialEq),
    )]
    struct Name(String);
    
    // Custom error type for `Name` validation.
    // You can use `thiserror` or similar crates to provide more detailed error messages.
    #[derive(Debug, PartialEq)]
    enum NameError {
        TooShort { min: usize, length: usize },
        TooLong { max: usize, length: usize },
    }
    
    // Validation function for `Name` that checks its length.
    fn validate_name(name: &str) -> Result<(), NameError> {
        const MIN: usize = 3;
        const MAX: usize = 10;
        let length = name.encode_utf16().count();
    
        if length < MIN {
            Err(NameError::TooShort { min: MIN, length })
        } else if length > MAX {
            Err(NameError::TooLong { max: MAX, length })
        } else {
            Ok(())
        }
    }

    With this enhancement, users have full control over the error type and how errors are constructed during validation, making the error handling process more powerful and adaptable to different use cases.

    Transition from fallible::new() to ::try_new()

    In version 0.4.3, the fallible ::new() constructor was deprecated but still available. Now, it has been fully replaced by ::try_new(). For example, to initialize a Name from the previous example:

    let name = Name::try_new("Anton").unwrap();

    This change ensures a more consistent and explicit error-handling approach when creating instances.
    Note that ::new() is still used as a non-fallible constructor if there a newtype has no validation.

    The sponsors ❤️

    A big shoutout to the true sponsors of this release - my in-laws! Thanks for taking care of my wife and kid, giving me a free weekend to work on Nutype!

    Links

    Open source →
    Release notes
    • [FEATURE] Added support for custom error types and validation functions via the error and with attributes.
    • [BREAKING] Replaced lazy_static with std::sync::LazyLock for regex validation. This requires Rust 1.80 or higher and may cause compilation issues on older Rust versions due to the use of std::sync::LazyLock. If upgrading Rust isn't an option, you can still use lazy_static explicitly as a workaround.
    • [BREAKING] The fallible ::new() constructor has been fully replaced by ::try_new().
    Open source →
  8. 0.5.0-beta.2 25 Aug 2024 pre-release

    Nothing published for this version

  9. 0.5.0-beta.1 24 Aug 2024 pre-release

    Nothing published for this version

  10. 0.4.3 06 Jul 2024
    Release notes

    Changes

    • Support generics
    • [DEPRECATION] Fallible (when a newtype has validation) constructor ::new() is deprecated. Users should use ::try_new() instead.
    • [FIX] Use absolute path for ::core::result::Result when generating code for derive(TryFrom).

    Highlights

    This release comes with support of generic types for newtypes!
    The example below defines SortedNotEmptyVec<T> wrapper around Vec<T> which is guaranteed to be not empty and sorted.
    Note, that type bound T: Ord enables invocation of v.sort() in the sanitization function.

    use nutype::nutype;
    
    #[nutype(
        sanitize(with = |mut v| { v.sort(); v }),
        validate(predicate = |vec| !vec.is_empty()),
        derive(Debug, PartialEq, AsRef),
    )]
    struct SortedNotEmptyVec<T: Ord>(Vec<T>);
    
    let wise_friends = SortedNotEmptyVec::try_new(vec!["Seneca", "Zeno", "Plato"]).unwrap();
    assert_eq!(wise_friends.as_ref(), &["Plato", "Seneca", "Zeno"]);
    
    let numbers = SortedNotEmptyVec::try_new(vec![4, 2, 7, 1]).unwrap();
    assert_eq!(numbers.as_ref(), &[1, 2, 4, 7]);

    Links

    Open source →
    Release notes
    • Support generics
    • [DEPRECATION] Fallible constructor ::new() is deprecated. Users should use ::try_new() instead.
    • [FIX] Use absolute path for ::core::result::Result when generating code for derive(TryFrom).
    Open source →
  11. 0.4.3-beta.1 01 Jul 2024 pre-release

    Nothing published for this version

  12. 0.4.2 07 Apr 2024
    Release notes
    • Support no_std ( the dependency needs to be declared as nutype = { default-features = false } )
    • Support integration with arbitrary crate (see arbitrary feature).
      • Support Arbitrary for integer types
      • Support Arbitrary for float types
      • Support Arbitrary for string inner types
      • Support Arbitrary for any inner types
    • Possibility to specify boundaries (greater, greater_or_equal, less, less_or_equal, len_char_min, len_char_max) with expressions or named constants.
    • Add #[inline] attribute to trivial functions
    • Improve error messages
    Open source →
  13. 0.4.1 07 Apr 2024
    Release notes
    • Failed release. Includes everything from v0.4.2 except support of Arbitrary for String based types.
    Open source →
  14. 0.4.1-beta.1 28 Jan 2024 pre-release

    Nothing published for this version

  15. 0.4.0 20 Nov 2023
    Release notes
    • Support of arbitrary inner types with custom sanitizers and validators.
    • Add numeric validator greater
    • Add numeric validator less
    • [BREAKING] Removal of asterisk derive
    • [BREAKING] Use commas to separate high level attributes
    • [BREAKING] Traits are derived with #[nutype(derive(Debug))]. The regular #[derive(Debug)] syntax is not supported anymore.
    • [BREAKING] Validator with has been renamed to predicate to reflect the boolean nature of its range
    • [BREAKING] String validator min_len has been renamed to len_char_min to reflect that is based on UTF8 chars.
    • [BREAKING] String validator max_len has been renamed to len_char_max to reflect that is based on UTF8 chars.
    • [BREAKING] Rename numeric validator max to less_or_equal
    • [BREAKING] Rename numeric validator min to greater_or_equal
    • [BREAKING] Rename error variants to follow the following formula: <ValidationRule>Violated. This implies the following renames:
      • TooShort -> LenCharMinViolated
      • TooLong -> LenCharMaxViolated
      • Empty -> NotEmptyViolated
      • RegexMismatch -> RegexViolated
      • Invalid -> PredicateViolated
      • TooBig -> LessOrEqualViolated
      • TooSmall -> GreaterOrEqualViolated
      • NotFinite -> FiniteViolated
    • Better error messages: in case of unknown attribute, validator or sanitizer the possible values are listed.
    • [FIX] Make derived Deserialize work with RON format
    Open source →
  16. 0.4.0-beta.2 28 Aug 2023 pre-release

    Nothing published for this version

  17. 0.4.0-beta.1 27 Aug 2023 pre-release

    Nothing published for this version

  18. 0.3.1 30 Jun 2023
    Release notes
    • Support deriving of Deref
    Open source →
  19. 0.3.0 25 Jun 2023
    Release notes
    • [BREAKING] min_len and max_len validators run against number of characters in a string (val.chars().count()), not number of bytes (val.len()).
    • Add finite validation for float types which checks against NaN and infinity.
    • Support deriving of Default
    • Support deriving of Eq and Ord on float types (if finite validation is present)
    • Support deriving of TryFrom for types without validation (in this case Error type is std::convert::Infallible)
    Open source →
  20. 0.2.0 13 Apr 2023
    Release notes
    • [BREAKING] Rename string validator present -> not_empty. Rename error variant Missing -> Empty.
    • [BREAKING] Rename feature serde1 to serde.
    • Introduce new_unchecked feature flag, that allows to bypass sanitization and validation.
    • Support derive of JsonSchema of schemars crate (requires schemars08 feature).
    • Support string validation with regex (requires regex feature).
    Open source →
  21. 0.1.1 11 Feb 2023
    Release notes
    • Initial release
    Open source →
  22. 0.1.0 03 Oct 2022

    Nothing published for this version

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive