# Validation

## Action Input Validation

You can validate input data in custom actions using Zod schemas. The input is validated before the action handler executes:

```typescript
// quickback/features/applications/actions/advanceStage.ts
import { z } from 'zod';
import { defineAction } from '../.quickback/define-action';

export default defineAction({
  description: "Move application to the next pipeline stage",
  input: z.object({
    stage: z.enum(["screening", "interview", "offer", "hired"]),
    notes: z.string().min(1).max(500).optional(),
  }),
  access: { roles: ["owner", "hiring-manager"] },
  execute: async ({ db, record, ctx, input }) => {
    // input is validated against the Zod schema before execution
    return record;
  },
});
```

If validation fails, the API returns a `400 Bad Request` with details about which fields failed.

See [Actions](/define/actions) for the full action definition reference.

> **Planned: Field-Level Validation**
>
> Field-level validation rules in `defineTable()` (e.g., `minLength`, `maxLength`, `enum`) are planned for a future release. Today, use Zod schemas in actions for input validation, and rely on your Drizzle schema constraints (`.notNull()`, column types) for database-level enforcement.

