Migration

Nestia & Typia Migration

How tsgonest migrate converts Nestia route decorators and Typia branded types.

tsgonest migrate converts Nestia's @nestia/core decorators to standard NestJS decorators and rewrites Typia's branded type imports to @tsgonest/types. Since tsgonest mirrors Typia's tag names, your type annotations remain unchanged.

Route Decorator Replacements

NestiaNestJS (after migration)
@TypedRoute.Get()@Get()
@TypedRoute.Post()@Post()
@TypedRoute.Put()@Put()
@TypedRoute.Patch()@Patch()
@TypedRoute.Delete()@Delete()

Path arguments are preserved: @TypedRoute.Get(':id') becomes @Get(':id').

Parameter Decorator Replacements

NestiaNestJS (after migration)
@TypedBody()@Body()
@TypedQuery()@Query()
@TypedParam<T>('name')@Param('name')
@TypedHeaders()@Headers()

Type parameters are dropped since tsgonest infers types from the parameter's TypeScript type annotation.

FormData Handling

Nestia's @TypedFormData.Body() is converted to @FormDataBody() from @tsgonest/runtime, with a @UseInterceptors(FormDataInterceptor) added to the method:

Before

import { TypedFormData } from '@nestia/core';

@Controller('upload')
export class UploadController {
  @Post()
  upload(@TypedFormData.Body() body: UploadDto) {}
}

After

import { FormDataBody, FormDataInterceptor } from '@tsgonest/runtime';
import { Controller, Post, UseInterceptors } from '@nestjs/common';

@Controller('upload')
export class UploadController {
  @UseInterceptors(FormDataInterceptor)
  @Post()
  upload(@FormDataBody() body: UploadDto) {}
}

Multer factory arguments are preserved: @TypedFormData.Body(() => multer()) becomes @FormDataBody(() => multer()).

Typia Call Removal

Runtime Typia calls are removed or replaced, since tsgonest handles validation and serialization at compile time:

Typia callReplacementNotes
typia.assert<T>(input)inputValidation is handled by tsgonest's compile-time transforms
typia.is<T>(input)inputSame as above
typia.json.stringify<T>(data)JSON.stringify(data)tsgonest generates fast serializers automatically
typia.json.assertStringify<T>(data)JSON.stringify(data)Validation + serialization handled by tsgonest
typia.json.assertParse<T>(input)JSON.parse(input)TODO added — add manual validation if needed

Branded Types Import Rewrite

tsgonest's @tsgonest/types package mirrors Typia's tag names, so type annotations don't change — only the import source is rewritten:

// Before
import { tags } from 'typia';

// After
import { tags } from '@tsgonest/types';

Your branded type annotations (tags.MinLength<1>, tags.Format<"email">, etc.) remain exactly the same.

tags.TagBase (Custom Validators)

If your code uses tags.TagBase<> for custom Typia validators, a TODO is added to the migration report. Custom validators need manual migration to tsgonest's Validate<typeof fn> pattern.

@SwaggerCustomizer

Nestia's @SwaggerCustomizer() decorator is removed with a TODO. Configure OpenAPI customizations in tsgonest.config.ts or via JSDoc tags instead.

Config and Tooling Changes

ts-patch Removal

Nestia/Typia projects use ts-patch to hook into the TypeScript compiler. Since tsgonest replaces the compiler entirely, ts-patch is no longer needed.

The migration removes ts-patch and typescript-transform-paths from package.json and strips plugin entries from tsconfig.json.

Nestia Config

Nestia config files (nestia.config.ts, nestia.config.js, etc.) are removed. Their equivalent settings are generated in tsgonest.config.ts:

Nestia configtsgonest config
input (controllers glob)controllers.include
output (SDK output)Not applicable (tsgonest doesn't generate SDK)
swagger.outputopenapi.output
swagger.securityopenapi.securitySchemes (auto-detected from decorators)

Full Before/After Example

Before (Nestia + Typia)

import { TypedRoute, TypedBody, TypedQuery } from '@nestia/core';
import { Controller } from '@nestjs/common';
import { tags } from 'typia';

interface SearchQuery {
  q: string & tags.MinLength<1>;
  page: number & tags.Minimum<1>;
}

interface CreateUserInput {
  email: string & tags.Format<'email'>;
  name: string & tags.MinLength<1>;
}

@Controller('users')
export class UsersController {
  @TypedRoute.Get()
  findAll(@TypedQuery() query: SearchQuery) {
    return this.usersService.findAll(query);
  }

  @TypedRoute.Post()
  create(@TypedBody() body: CreateUserInput) {
    return this.usersService.create(body);
  }
}

After (tsgonest)

import { Controller, Get, Post, Query, Body } from '@nestjs/common';
import { tags } from '@tsgonest/types';

interface SearchQuery {
  q: string & tags.MinLength<1>;
  page: number & tags.Minimum<1>;
}

interface CreateUserInput {
  email: string & tags.Format<'email'>;
  name: string & tags.MinLength<1>;
}

@Controller('users')
export class UsersController {
  @Get()
  findAll(@Query() query: SearchQuery) {
    return this.usersService.findAll(query);
  }

  @Post()
  create(@Body() body: CreateUserInput) {
    return this.usersService.create(body);
  }
}

The type annotations are identical — only imports and decorators changed.

On this page