SponsorsTable of ContentsGetting StartedInstallationMigration guide
Usage
CoerceLiteralsStringsNumbersBigIntsNaNsBooleansDatesEnumsOptionalsNullablesObjectsArraysUnionsRecordsMapsSetsIntersectionsRecursive typesPromisesInstanceofFunctionsPreprocess
Schema methods
Custom schemas
Guides and Concepts
Error HandlingComparisonEcosystem
Contributing
ChangelogCode of ConductLICENSE
Links
Clerk
⌘+J

© 2025 Zod


Designed in Earth-616

Build by oeri

Records

Record schemas are used to validate types such as Record<string, number>. This is particularly useful for storing or caching items by ID.

const User = z.object({ name: z.string() });
 
const UserStore = z.record(z.string(), User);
type UserStore = z.infer<typeof UserStore>;
// => Record<string, { name: string }>

The schema and inferred type can be used like so:

const userStore: UserStore = {};
 
userStore["77d2586b-9e8e-4ecf-8b21-ea7e0530eadd"] = {
  name: "Carlotta"
}; // passes
 
userStore["77d2586b-9e8e-4ecf-8b21-ea7e0530eadd"] = {
  whatever: "Ice cream sundae"
}; // TypeError

A note on numerical keys

While z.record(keyType, valueType) is able to accept numerical key types and TypeScript's built-in Record type is Record<KeyType, ValueType>, it's hard to represent the TypeScript type Record<number, any> in Zod.

As it turns out, TypeScript's behavior surrounding [k: number] is a little unintuitive:

const testMap: { [k: number]: string } = {
  1: "one"
};
 
for (const key in testMap) {
  console.log(`${key}: ${typeof key}`);
}
// prints: `1: string`

As you can see, JavaScript automatically casts all object keys to strings under the hood. Since Zod is trying to bridge the gap between static and runtime types, it doesn't make sense to provide a way of creating a record schema with numerical keys, since there's no such thing as a numerical key in runtime JavaScript.

On This Page

Records

Edit this page on GitHub