Orval 코드 생성 시 500개 파일 diff가 생긴다면

Orval 코드 생성 시 500개 파일 diff가 생긴다면

April 1, 2026

500개 파일이 바뀌었는데, 실제 변경은 0줄

PR을 올렸는데 Changed files가 500개가 넘었던 적 있으신가요?

저희 프로젝트에서는 Orval을 사용해 OpenAPI 스펙으로부터 API 서비스 코드를 자동 생성하고 있어요. API 타입, 요청 함수, React Query 훅까지 한 번에 만들어주니까 편하긴 한데, 어느 날 PR을 열었더니 파일 500여 개에 diff가 잡혀 있었습니다.

실제로 바뀐 비즈니스 로직은 하나도 없었어요. 원인은 Orval이 모든 생성 파일 상단에 삽입하는 주석 헤더의 OpenAPI spec version: 1.1.6d 한 줄이었습니다. 이 값은 백엔드에서 Swagger 문서를 설정할 때 필수로 지정하는 스펙 버전인데, 백엔드가 이 스펙 버전을 올릴 때마다 Orval로 생성된 모든 파일의 헤더가 바뀌는 거예요.

v1.1.5v1.1.6처럼 눈에 띄는 버전 변경이라면 감수할 수도 있겠지만, 실제로는 v1.1.6av1.1.6b처럼 패치 수준의 변경에서도 500개 파일 전체에 diff가 생깁니다.

진짜 문제는 diff 수가 아니라 리뷰가 불가능해지는 것

파일이 500개 바뀌는 것 자체보다, 그로 인해 생기는 부수적인 문제가 더 컸어요.

  • PR 리뷰 불가능: 실제 비즈니스 로직 변경이 헤더 변경 500건 사이에 묻힙니다. 리뷰어가 “진짜 변경”을 찾아 헤매야 해요
  • Git 히스토리 오염: git blame으로 코드 변경 이력을 추적할 때, 의미 없는 헤더 변경이 끼어들어요
  • 리뷰어 피로: 자동 생성 파일이라 어차피 무시해야 하는 건 알지만, 500개를 스크롤하면서 “이건 괜찮겠지”를 반복하는 건 은근한 부담이에요

결국 핵심 질문은 하나였습니다. Orval이 생성하는 헤더에서 OpenAPI spec version 줄만 제거할 수 있는가?

Orval 소스에서 찾은 해결 단서

이 질문에 답하려면 Orval의 헤더 생성 방식을 알아야 했어요. 공식 문서의 output configuration에서 header 옵션을 찾아봤지만, 구체적인 사용법이 잘 드러나지 않았습니다. 그래서 빌드된 소스 코드를 직접 열어봤어요.

node_modules/.pnpm/orval*/node_modules/orval/dist/index.js에서 헤더 생성 로직을 찾을 수 있었습니다. (Orval 소스 코드의 빌드 결과물이에요.)

var getDefaultFilesHeader = ({ title, description, version } = {}) => [
  `Generated by ${package_default.name} v${package_default.version}`,
  `Do not edit manually.`,
  ...(title ? [title] : []),
  ...(description ? [description] : []),
  ...(version ? [`OpenAPI spec version: ${version}`] : []), 
];

version 파라미터가 있으면 OpenAPI spec version: ... 줄을 추가하는 구조였어요. 그리고 바로 아래에서 output.override.header 옵션이 세 가지 모드를 지원한다는 것도 확인했습니다.

header: outputOptions.override?.header === false
  ? false // 헤더 완전 제거
  : isFunction(outputOptions.override?.header)
    ? outputOptions.override?.header // 커스텀 함수
    : getDefaultFilesHeader; // 기본값

커스텀 함수를 넘기면 원하는 정보만 골라 남길 수 있겠다는 생각이 들었어요.

커스텀 header 함수로 해결하기

header: false로 완전히 제거하는 방법도 있었지만, “Do not edit manually” 경고는 남겨두는 게 팀에게 유용하다고 판단했어요. 자동 생성 파일을 수동으로 편집하다 다음 생성 시 덮어씌워지는 실수를 막아주니까요.

그래서 커스텀 함수로 version 파라미터만 무시하는 방식을 선택했습니다.

// orval.config.ts
const header = ({
  title,
  description,
}: {
  title?: string;
  description?: string;
}) => [
  `Generated by orval`,
  `Do not edit manually.`,
  ...(title ? [title] : []),
  ...(description ? [description] : []),
  // version(OpenAPI spec version) 제외
];

저희 프로젝트에는 API 설정이 여러 개(baseApi는 메인 API, pyApi는 Python 기반 AI 서버)인데, 각각에 동일한 header 함수를 넣어줬어요.

// orval.config.ts
export default defineConfig({
  baseApi: {
    output: {
      override: {
        header,
        // ... 기타 설정
      },
    },
    // ...
  },
  pyApi: {
    output: {
      override: {
        header,
        // ... 기타 설정
      },
    },
    // ...
  },
});

적용 후 생성된 파일의 헤더는 이렇게 바뀝니다.

Before: 스펙 버전과 Orval 버전이 포함되어, 어느 쪽이든 변경될 때마다 전 파일에 diff 발생

/**
 * Generated by orval v7.11.2
 * Do not edit manually.
 * eXemble-AIC
 * OpenAPI spec version: 1.1.6d
 */

After: 변동 요소를 제거한 안정적인 헤더

/**
 * Generated by orval
 * Do not edit manually.
 * eXemble-AIC
 */

Orval 버전(v7.11.2)도 함께 빠졌는데, 이것 역시 Orval 자체를 업데이트할 때마다 전 파일 diff를 유발하는 원인이었기 때문에 의도적으로 제외했어요.

적용 결과

Orval을 실행하는 스크립트(pnpm generate:api)를 돌려보니, 생성된 파일에서 스펙 버전 줄이 깔끔하게 사라진 걸 확인할 수 있었어요. 프로젝트명(eXemble-AIC, OpenAPI 스펙의 title 필드)과 “Do not edit manually” 경고는 그대로 유지되고요.

이후 스펙 버전이 v1.1.6dv1.1.6e로 올라가는 상황에서도, 프론트엔드 자동 생성 파일에는 더 이상 헤더 때문에 diff가 발생하지 않습니다. PR에는 실제로 변경된 API 타입과 요청 함수만 남게 됐어요. 500개가 아니라, 진짜 바뀐 파일만요. git blame에 헤더 변경 커밋이 끼어드는 일도 사라졌고, 리뷰어가 500개 파일을 스크롤할 필요도 없어졌습니다.

레퍼런스

On this page