Record vs class vs struct in C#
C# gives you multiple ways to represent data. Instead of memorizing every rule, I use a few simple heuristics when building backend models.
1. Classes: the default for rich domain objects
If the type has behavior, invariants, or lifecycle, I default to class:
- Entities tracked by EF Core.
- Services and domain objects with methods.
- Types that will evolve over time.
2. Records: great for immutable data shapes
I like record (especially record class) for:
- Request/response DTOs.
- Value objects passed around in pipelines.
- Configuration snapshots.
Value-based equality and with-expressions make them nice for “data with intent”.
3. Structs: niche but useful
I use struct rarely in backend code:
- Small, truly value-like types (e.g., strongly-typed IDs, coordinates).
- Where allocation pressure is proven to be an issue and measured.
Prematurely sprinkling structs around can make copying semantics and boxing tricky.
4. A quick decision rule
- Needs identity/behavior and will be mutated? → class.
- Mostly immutable data, compared by value, flows through pipelines? → record.
- Tiny numeric-ish value with strong semantics and performance constraints? → struct.