NanoId

Dosaic.Extensions.NanoIds provides a strongly-typed NanoId value type for use across Dosaic services. It wraps NanoidDotNetarrow-up-right to generate compact, URL-safe, unique identifiers and adds first-class support for JSON and YAML serialization, entity decoration via attributes, collision-safe length presets, and implicit conversion to/from string.

Installation

dotnet add package Dosaic.Extensions.NanoIds

Or add a package reference directly to your .csproj:

<PackageReference Include="Dosaic.Extensions.NanoIds" Version="" />

Features

  • Strongly-typed IDNanoId is a distinct type, not a plain string, preventing accidental ID mix-ups across entity types.

  • No-look-alike alphabet — uses an alphabet that excludes visually ambiguous characters (e.g. 0, O, I, l) for safer human-readable IDs.

  • Attribute-driven generation — decorate any class with [NanoId(length)] or [NanoId(length, "prefix_")] and generate correctly-sized, prefixed IDs with a single call.

  • Pre-calculated safe lengthsNanoIdConfig.Lengths documents the number of IDs needed to reach a 1 % collision probability for each ID length (L2–L24).

  • Full serialization support — built-in JsonConverter and IYamlConverter so NanoId serializes as a plain string in both JSON and YAML.

  • Implicit string conversions — assign a string literal to a NanoId variable and vice versa without an explicit cast.

  • Value semantics — implements IComparable, IComparable<NanoId>, and IEquatable<NanoId> with == / != operator support.

  • INanoId interface — a lightweight marker interface for entity classes that expose a NanoId Id property.

Core Types

NanoId

The central value type. Wraps a string value and exposes factory methods for generating new IDs.

INanoId

Implement this interface on any entity class that owns a NanoId primary key:

NanoIdAttribute

Decorate entity classes with [NanoId] to configure the length (and optional prefix) of IDs generated for that type.

Parameter
Type
Description

length

byte

Number of random characters to generate

prefix

string

Optional string prepended to every generated ID (default: "")

The LengthWithPrefix property gives the total stored length:

NanoIdConfig

Static configuration used internally during ID generation.

NanoIdConfig.Lengths.NoLookAlikeDigitsAndLetters

Pre-calculated constants that map an ID length to the number of IDs required to reach a 1 % collision probability. Use these constants instead of magic numbers.

Constant
Length
IDs before ~1% collision

L2

2

6

L3

3

48

L4

4

340

L5

5

2 K

L6

6

16 K

L7

7

116 K

L8

8

817 K

L9

9

5 M

L10

10

40 M

L11

11

280 M

L12

12

1 B

L13

13

13 B

L14

14

96 B

L15

15

673 B

L16

16

4 T

L17

17

32 T

L18

18

230 T

L19

19

1 616 T

L20

20

11 312 T

L24

24

27 161 781 T

Figures are based on zelark.github.io/nano-id-ccarrow-up-right.

Usage

Defining entity types

Generating new IDs

Use the generic overload when the type is known at compile time:

Use the Type overload when the type is only known at runtime (e.g. dynamic seeding scripts):

NewId throws ArgumentException if the target type does not have a [NanoId] attribute.

Generating IDs for database seed data

A common pattern is to pre-generate a fixed set of readable IDs for seed data files. The test project ships an [Explicit] helper test for exactly this purpose:

Run it once with your preferred type, then copy the output into your seed-data files.

Value semantics

NanoId supports all standard equality and comparison operations:

Passing a non-NanoId object to CompareTo(object) throws ArgumentException. Constructing a NanoId with a null string throws ArgumentNullException.

Implicit string conversions

Serialization

NanoId serializes as a plain JSON/YAML string out of the box. No extra configuration is required when using Dosaic's default serialization stack.

JSON

YAML

ToString and span formatting

No plugin configuration required

Dosaic.Extensions.NanoIds is a pure library — it does not register any DI services or middleware and requires no entries in appsettings.yml. Simply reference the package and use the types directly.

Last updated