> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dottxt.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Bounded Arrays

> Use array limits to control output size, cost, and downstream complexity.

Without `minItems` and `maxItems`, the model decides how many array elements to produce. In practice, this means some requests return zero items (breaking downstream consumers that expect at least one) and others return dozens (blowing up storage, UI layouts, or token budgets). Array bounds make the contract explicit: you get at least N and at most M items, every time.

Item-level constraints matter too. An unbounded array of unconstrained strings is effectively uncontrolled output. Adding `pattern` and `minLength`/`maxLength` to the items turns the array into a well-defined, predictable structure.

## Use case

Generating article tags for search indexing. You need 3-8 tags, each short and lowercase, suitable for a tag-based search index.

## Schema pattern

<CodeGroup>
  ```json JSON Schema theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  {
    "type": "object",
    "properties": {
      "tags": {
        "type": "array",
        "items": {
          "type": "string",
          "pattern": "^[a-z0-9-]{2,24}$"
        },
        "minItems": 3,
        "maxItems": 8
      }
    },
    "required": ["tags"],
    "additionalProperties": false
  }
  ```

  ```python Pydantic theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  from pydantic import BaseModel, ConfigDict, Field, model_validator

  class TagsPayload(BaseModel):
      model_config = ConfigDict(extra="forbid")
      tags: list[str] = Field(..., min_length=3, max_length=8)

      @model_validator(mode="after")
      def validate_tags(self):
          if len(set(self.tags)) != len(self.tags):
              raise ValueError("tags must be unique")
          for tag in self.tags:
              if len(tag) < 2 or len(tag) > 24:
                  raise ValueError("tag length must be 2-24")
              import re
              if re.match(r"^[a-z0-9-]{2,24}$", tag) is None:
                  raise ValueError("tag must match slug pattern")
          return self
  ```

  ```typescript Zod theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  import { z } from "zod";

  const tagsPayloadSchema = z.object({
    tags: z.array(z.string().regex(/^[a-z0-9-]{2,24}$/)).min(3).max(8),
  }).strict().superRefine((data, ctx) => {
    if (new Set(data.tags).size !== data.tags.length) {
      ctx.addIssue({ code: z.ZodIssueCode.custom, message: "tags must be unique" });
    }
  });
  ```
</CodeGroup>

## Example output

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "tags": [
    "password-reset",
    "mobile-app",
    "ios",
    "auth-flow"
  ]
}
```

## Why this works

`minItems: 3` guarantees you always have enough tags for meaningful search indexing. `maxItems: 8` caps generation cost and keeps tag lists manageable in UI rendering.

The item-level `pattern: "^[a-z0-9-]{2,24}$"` enforces a slug format: lowercase, hyphenated, with no spaces. That means tags are already normalized for your search index without any post-processing.

## Related docs

* [Object reference](/json-schema/reference/object)
* [String reference](/json-schema/reference/string)
