Arkos.js v1.7-rc is out 🥳

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

Uanela Como
Uanela Como

Fullstack Developer@Mesquita Group & SuperM7.com Founder

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.ts

Going 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.

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 fileHook key
login.schema.ts / login.dto.tslogin
signup.schema.ts / signup.dto.tssignup
update-me.schema.ts / update-me.dto.tsupdateMe
update-password.schema.ts / update-password.dto.tsupdatePassword
// 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-hook

The warning disappears once the subdirectory is empty or the files are no longer auto-detected.

Quick Checklist

  • Identify all modules with a dtos/ or schemas/ subdirectory
  • Import each validator into the corresponding *.router.ts file
  • 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/or schemas/ subdirectories