---
title: Choose strict() vs strip() for Unknown Keys
impact: MEDIUM-HIGH
impactDescription: Default passthrough mode leaks unexpected data; strict() catches schema mismatches, strip() silently removes extras
tags: object, strict, strip, passthrough
---

## Choose strict() vs strip() for Unknown Keys

By default, Zod objects use `.strip()` behavior, silently removing unrecognized keys. This can hide schema/data mismatches. Use `.strict()` to reject unknown keys (catching errors) or explicitly use `.strip()` to document the intention.

**Default behavior (strip - silent removal):**

```typescript
import { z } from "zod";

const userSchema = z.object({
  id: z.string(),
  name: z.string(),
});

const input = {
  id: "123",
  name: "John",
  role: "admin", // Extra field
  secretToken: "abc123", // Another extra field
};

const user = userSchema.parse(input);
// { id: '123', name: 'John' }
// Extra fields silently removed - was this intentional?
```

**Using strict() to catch schema mismatches:**

```typescript
import { z } from "zod";

const userSchema = z
  .object({
    id: z.string(),
    name: z.string(),
  })
  .strict();

const input = {
  id: "123",
  name: "John",
  role: "admin",
};

userSchema.parse(input);
// ZodError: Unrecognized key(s) in object: 'role'

// This catches:
// - Client sending fields the server doesn't expect
// - Schema out of sync with actual data structure
// - Typos in field names
```

**When to use each mode:**

```typescript
// strict() - Catch unexpected data (API contracts)
const apiRequestSchema = z
  .object({
    action: z.string(),
    payload: z.unknown(),
  })
  .strict(); // Fail if client sends unknown fields

// strip() - Clean up data (explicit intention)
const dbInsertSchema = z
  .object({
    name: z.string(),
    email: z.string(),
  })
  .strip(); // Explicitly remove metadata before insert

// passthrough() - Keep everything (pass-through proxy)
const proxySchema = z
  .object({
    id: z.string(),
  })
  .passthrough(); // Keep fields we don't validate

const input = { id: "123", extra: "data" };
proxySchema.parse(input); // { id: '123', extra: 'data' }
```

**Choosing the right mode:**

| Mode                 | Behavior            | Use When                                     |
| -------------------- | ------------------- | -------------------------------------------- |
| `.strict()`          | Reject unknown keys | API contracts, security-sensitive, debugging |
| `.strip()` (default) | Remove unknown keys | General validation, data cleaning            |
| `.passthrough()`     | Keep unknown keys   | Proxying, partial validation                 |

**Handling specific unknown keys:**

```typescript
const schema = z
  .object({
    id: z.string(),
    name: z.string(),
  })
  .catchall(z.unknown()); // Allow any additional fields of any type

// Or restrict additional fields to specific type
const metadataSchema = z
  .object({
    id: z.string(),
  })
  .catchall(z.string()); // Only allow string extras
```

**When NOT to use this pattern:**

- `.strict()`: When forwarding data to another system that may add fields
- `.passthrough()`: When you need to ensure only known fields are stored

Reference: [Zod API - Objects](https://zod.dev/api#objects)
