Skip to main content
Use "type": "array" for ordered lists.

Core array keywords

KeywordWhat it does
prefixItemsPositional schemas for tuple-style arrays
itemsSchema for each array element
minItems / maxItemsBounds array length
contains, minContains, maxContains, uniqueItems and unevaluatedItems are not supported right now. If you have a use case that requires them, reach out to us.

Example

{
  "type": "object",
  "properties": {
    "values": {
      "type": "array",
      "items": {
        "type": "number"
      },
      "minItems": 1,
      "maxItems": 5
    }
  },
  "required": ["values"],
  "additionalProperties": false
}
from typing import Annotated
from pydantic import BaseModel, ConfigDict, Field

class Payload(BaseModel):
    model_config = ConfigDict(extra="forbid")

    values: Annotated[list[float], Field(min_length=1, max_length=5)]
import { z } from "zod";

const payloadSchema = z
  .object({
    values: z.array(z.number()).min(1).max(5),
  })
  .strict();
For capped payload size, always set maxItems. The default value of minItems is 0.

prefixItems

Use prefixItems for tuple-style arrays where position matters:
{
  "type": "object",
  "properties": {
    "metric": {
      "type": "array",
      "prefixItems": [
        { "type": "string", "enum": ["latency_ms", "error_count"] },
        { "type": "number", "minimum": 0 }
      ],
      "items": false
    }
  },
  "required": ["metric"],
  "additionalProperties": false
}
from typing import Annotated, Literal
from pydantic import BaseModel, ConfigDict, Field

class Payload(BaseModel):
    model_config = ConfigDict(extra="forbid")

    metric: tuple[Literal["latency_ms", "error_count"], Annotated[float, Field(ge=0)]]
import { z } from "zod";

const payloadSchema = z
  .object({
    metric: z.tuple([z.enum(["latency_ms", "error_count"]), z.number().min(0)]),
  })
  .strict();
This example enforces a two-element array: a metric name followed by a numeric value.