Migrate Validators to Route Hooks
DTOs and Zod schema subdirectories are going away in v2.0. Here's how to move your validators into the route hook in one file — and drop the folders for good.
Written by

At
Wed May 27 2026
Starting in v2.0, Arkos will stop auto-loading validators from the dtos/ and schemas/ subdirectories. Instead, you attach them directly to the relevant operation inside your *.router.ts file using the hook export.
This guide walks through the migration for both Zod schemas and class-based DTOs.
What Is Changing
Previously, Arkos auto-loaded validators from dedicated subdirectories:
src/modules/post/
├── dtos/
│ ├── create-post.dto.ts
│ └── update-post.dto.ts
└── schemas/
├── create-post.schema.ts
└── update-post.schema.tsGoing forward, validators are declared inline inside the hook export in your router file via the validation key. The subdirectory auto-loading will be removed in v2.0.
Migration Steps
1. Open your router file
Your router file lives at src/modules/<model>/<model>.router.ts.
2. Import your validators
Move your existing DTO class or Zod schema imports into the router file.
3. Add validation to the relevant hook operation
Use the validation key on any operation (createOne, updateOne, etc.) and pass your validator under body.
4. Delete the old dtos/ or schemas/ subdirectory (optional but recommended)
Once all validators are referenced through the hook, the subdirectories are no longer needed.
Examples
Zod Schemas
Before
src/modules/post/schemas/
├── create-post.schema.ts ← auto-loaded for createOne
└── update-post.schema.ts ← auto-loaded for updateOne// src/modules/post/post.router.ts
import { ArkosRouter, RouteHook } from "arkos";
export const hook: RouteHook = {
findMany: { authentication: false },
};
const router = ArkosRouter();
export default router;After
// src/modules/post/post.router.ts
import { ArkosRouter, RouteHook } from "arkos";
import CreatePostSchema from "./schemas/create-post.schema";
import UpdatePostSchema from "./schemas/update-post.schema";
export const hook: RouteHook = {
findMany: { authentication: false },
createOne: {
validation: { body: CreatePostSchema },
},
updateOne: {
validation: { body: UpdatePostSchema },
},
};
const router = ArkosRouter();
export default router;Class-Based DTOs
Before
src/modules/post/dtos/
├── create-post.dto.ts ← auto-loaded for createOne
└── update-post.dto.ts ← auto-loaded for updateOne// src/modules/post/post.router.ts
import { ArkosRouter, RouteHook } from "arkos";
export const hook: RouteHook = {
findMany: { authentication: false },
};
const router = ArkosRouter();
export default router;After
// src/modules/post/post.router.ts
import { ArkosRouter, RouteHook } from "arkos";
import CreatePostDto from "./dtos/create-post.dto";
import UpdatePostDto from "./dtos/update-post.dto";
export const hook: RouteHook = {
findMany: { authentication: false },
createOne: {
validation: { body: CreatePostDto },
},
updateOne: {
validation: { body: UpdatePostDto },
},
};
const router = ArkosRouter();
export default router;Auth Module
The auth module uses dedicated file names. Map each file to its corresponding hook key:
| Old file | Hook key |
|---|---|
login.schema.ts / login.dto.ts | login |
signup.schema.ts / signup.dto.ts | signup |
update-me.schema.ts / update-me.dto.ts | updateMe |
update-password.schema.ts / update-password.dto.ts | updatePassword |
// src/modules/auth/auth.router.ts
import { ArkosRouter, RouteHook } from "arkos";
import LoginSchema from "./schemas/login.schema";
import SignupSchema from "./schemas/signup.schema";
import UpdateMeSchema from "./schemas/update-me.schema";
import UpdatePasswordSchema from "./schemas/update-password.schema";
export const hook: RouteHook<"auth"> = {
login: { validation: { body: LoginSchema } },
signup: { validation: { body: SignupSchema } },
updateMe: { validation: { body: UpdateMeSchema } },
updatePassword: { validation: { body: UpdatePasswordSchema } },
};
const router = ArkosRouter();
export default router;Combined Example (Auth + Validation + Rate Limiting)
You can freely combine validation with authentication, rateLimit, and disabled in the same operation:
// src/modules/auth/auth.router.ts
import { ArkosRouter, RouteHook } from "arkos";
import UpdateMeSchema from "./schemas/update-me.schema";
export const hook: RouteHook<"auth"> = {
login: { rateLimit: { windowMs: 15 * 60_000, max: 10 } },
signup: { disabled: true },
updateMe: { validation: { body: UpdateMeSchema } },
updatePassword: { rateLimit: { windowMs: 15 * 60_000, max: 10 } },
deleteMe: { disabled: true },
};
const router = ArkosRouter();
export default router;Deprecation Warning
If you still have validators in dtos/ or schemas/ subdirectories, Arkos will log a warning at startup:
[Warn] Found zod schemas (schemas/ folder) at the filepaths below, those patterns will stop
auto loading in v2.0: src/modules/post/schemas/
See migration guide at https://www.arkosjs.com/blog/migrate-validators-to-route-hookThe warning disappears once the subdirectory is empty or the files are no longer auto-detected.
Quick Checklist
- Identify all modules with a
dtos/orschemas/subdirectory - Import each validator into the corresponding
*.router.tsfile - Add a
validation: { body: YourValidator }key to each affected hook operation - Confirm the deprecation warning is gone at startup
- Remove the now-unused
dtos/and/orschemas/subdirectories
Tags: