A record models related data as a named, formally defined product type. Where a tuple groups values by position, a record gives every field a name, making domain shapes such as customers, addresses, and orders easier to read, pass around, and evolve. section 5.1 section 5.3
Figure 5.1 Illustrating product (AND) and sum (OR) types. A soccer player has a name, age, and a team, but their position on the field is either forward, midfield, or defense.
Product types combine facts with AND: a player has a name, age, and team. Sum types instead represent alternatives with OR. section 5.1
Define a record before creating it, then supply every field when constructing a value. Read fields through dot notation. The compiler checks field names and types, and can often infer the record type from the fields used. section 5.3.1 section 5.3.2
Define and use a person record
type Person = { FirstName : string LastName : string Age : int } let isaac = { FirstName = "Isaac" LastName = "Abraham" Age = 42 } let fullName = $"{isaac.FirstName} {isaac.LastName}" section 5.3.1
Record fields are immutable by default. To represent a changed state, copy an existing value with copy-and-update syntax and replace only the needed fields. Equality is structural and deep: records whose fields match compare equal. section 5.3.2
Copy an address with selected changes
let addressInDE = { theAddress with Town = "Berlin" Country = "DE" } section 5.3.2
Use records when the data shape has a meaningful name and is expected to live beyond a small local calculation:
- Choose records for everyday data modeling and public API definitions; use tuples for short-lived, simple groupings. section 5.5
- Compose records from other records, tuples, lists, and unions to describe nested or alternative domain data. section 5.3.1 section 8.4.3
- Keep behavior in functions and modules rather than treating a record as a class with embedded behavior. section 10.1.2
- Pattern-match only the fields relevant to a decision when named patterns improve readability over tuple matching. section 8.1.4
Records compile to .NET classes with getter-only properties and a constructor requiring every field. They can be created and consumed from C#. A [<Struct>] attribute makes a record a value type, but that choice should be performance-tested. section 5.3.3 section 11.2.1
For web input, a simple record can mirror raw JSON with primitive fields. Map that record through validation functions into a richer domain type, returning errors separately from successful handling. section 13.2.7











