웹 개발 데일리 브리핑 — 2026-10-28
Soshy··조회수 —

기준 시점: 2026-10-28 06:00 KST
조사 범위: 2026-10-27 06:00 ~ 2026-10-28 06:00 KST
추천 글 범위: 기준 시점 당시 최근 7일
1️⃣ 프론트엔드
Nuxt 4.6.3 보안 패치 출시 — 개발 서버의 비밀 정보 노출과 페이지 접근 제어 우회 등 취약점 5건 수정
- 발표일: 2026-10-27 — 정확한 게시 시각 미확인
- 버전: Nuxt 4.6.3
- 안정화 단계: 정식 패치 릴리스
- 변경 유형: 보안 수정 5건, 빌드 성능 최적화 및 버그 수정
- 영향받는 패키지:
nuxt,@nuxt/vite-builder,@nuxt/nitro-server - 원문: https://github.com/nuxt/nuxt/releases/tag/v4.6.3
Nuxt가 개발 서버의 파일 접근 제한과 서버 렌더링 과정의 접근 제어 문제를 수정한 4.6.3 버전을 공개했다.
이번 릴리스에는 다섯 건의 보안 수정이 포함됐다.
단순히 오래된 의존성을 업데이트하는 일반적인 패치와 달리, 개발 서버에서 비밀 정보가 노출될 수 있는 문제와 실제 페이지 접근 제어를 우회할 수 있는 문제가 함께 수정됐다.
특히 다섯 취약점의 영향 범위가 서로 다르다는 점에 주의해야 한다.
일부는 개발 서버에서만 발생한다.
반면 일부는 실제 배포된 Nuxt 애플리케이션의 페이지 접근 제어에 영향을 줄 수 있다.
따라서 모든 취약점을 동일한 위험으로 취급하기보다 어떤 실행 환경과 기능이 영향을 받는지 구분해야 한다.
1. 개발 서버의 클라이언트 오류 보고를 이용한 임의 파일 읽기
- 취약점: GHSA-x287-wcfc-q46c
- 심각도: Moderate
- 영향받는 버전:
@nuxt/vite-builder4.6.0 이상, 4.6.3 미만 - 수정 버전: 4.6.3
- 공식 보안 권고: https://github.com/nuxt/nuxt/security/advisories/GHSA-x287-wcfc-q46c
Nuxt 개발 서버는 브라우저에서 발생한 오류를 개발자에게 표시하기 위한 기능을 제공한다.
예를 들어 브라우저에서 모듈을 불러오지 못했거나 JavaScript 오류가 발생하면 관련 파일과 위치를 개발 서버에 전달할 수 있다.
문제는 개발 서버가 이러한 오류 보고에 포함된 파일 경로를 신뢰할 수 있다는 점이었다.
공격자가 임의의 파일 경로를 포함한 오류 보고를 만들 수 있다면 개발 서버가 해당 파일을 읽으려고 시도할 수 있었다.
이 과정에서 프로젝트의 .env 파일이나 개발자 컴퓨터에 저장된 민감한 파일이 노출될 가능성이 있었다.
이번 수정에서는 클라이언트가 전달한 파일 이름을 그대로 읽지 않고, 개발 서버가 실제로 관리하는 모듈 정보를 기준으로 파일을 확인하도록 변경했다.
다만 이 취약점은 개발 서버의 오류 처리 경로에 관한 것이다.
Nuxt의 일반적인 Production Build 전체가 동일한 방식으로 영향을 받는 것은 아니다.
또한 공격자가 개발 서버에 접근할 수 있어야 한다.
일반적으로 개발 서버를 로컬에서만 실행한다면 외부 접근 범위가 제한된다.
반면 개발 서버의 포트를 외부 네트워크에 직접 공개하거나 공용 개발 환경에서 사용한다면 위험이 증가할 수 있다.
2. Nitro 개발용 번들에서 비공개 Runtime Config 노출
- 취약점: GHSA-648h-gw55-m2g7
- 심각도: Moderate
- 영향받는 버전: Nuxt 3.x 및 Nuxt 4.6.3 미만의 4.x
- 수정 버전: 4.6.3
- 공식 보안 권고: https://github.com/nuxt/nuxt/security/advisories/GHSA-648h-gw55-m2g7
두 번째 문제는 개발 서버의 파일 제공 기능과 Nitro 개발용 번들의 관계에서 발생했다.
Nuxt는 서버에서 실행되는 설정과 브라우저에서 사용할 수 있는 설정을 구분한다.
대표적인 설정이 runtimeConfig다.
일반적으로 runtimeConfig.public에는 클라이언트에서 사용할 수 있는 값을 배치한다.
반면 비공개 Runtime Config에는 서버에서만 사용해야 하는 설정을 저장할 수 있다.
하지만 개발 과정에서 생성한 Nitro 번들에 이러한 정보가 포함되고, 해당 파일이 Vite의 파일 제공 경로를 통해 읽힐 수 있는 문제가 존재했다.
관련 경로에는 다음과 같은 형태가 포함된다.
/_nuxt/@fs/
공격자가 개발 서버에 접근할 수 있다면 Nitro 개발용 번들을 요청해 서버 전용 설정에 포함된 정보를 확인할 가능성이 있었다.
이번 수정에서는 개발 서버가 Nitro의 내부 출력 파일을 제공하지 않도록 파일 접근 제한을 강화했다.
중요한 제한사항은 다음과 같다.
- Nitro 2를 사용하는 개발 환경과 관련된다.
- 일반적인 Production 환경에는 동일하게 적용되지 않는다.
- Nitro 3은 해당 취약점의 영향 대상이 아니다.
- Nuxt 3.x는 지원이 종료돼 이번 릴리스에서 별도의 수정 버전이 제공되지 않는다.
따라서 Nuxt 3을 계속 사용하는 프로젝트라면 4.6.3으로 업데이트하는 것과 별도로 실제 마이그레이션 가능 여부를 검토해야 한다.
3. 개발 서버에서 자동 생성된 App Secret 노출
- 취약점: GHSA-3xf4-9g3c-4h4w
- 심각도: Moderate
- 영향받는 버전: Nuxt 4.6.0 이상, 4.6.3 미만
- 공식 보안 권고: https://github.com/nuxt/nuxt/security/advisories/GHSA-3xf4-9g3c-4h4w
Nuxt는 일부 기능에서 애플리케이션의 비밀값을 사용한다.
개발 환경에서는 이러한 값을 자동으로 생성할 수 있다.
문제는 생성된 App Secret이 개발 서버의 파일 제공 기능을 통해 접근 가능한 경로에 존재할 수 있었다는 점이다.
관련 파일은 다음과 같은 형태다.
.nuxt/app-secret
공격자가 해당 파일을 읽으면 비밀값을 기반으로 보호하는 개발 환경의 세션 등에 영향을 줄 수 있었다.
이번 수정에서는 생성된 App Secret을 개발 서버가 외부에 제공하지 않도록 차단했다.
하지만 이 취약점 역시 모든 Nuxt 배포에서 인증 정보가 노출된다는 의미는 아니다.
공식 보안 권고는 개발 환경에서 자동 생성된 Secret을 사용하는 조건과 관련된 문제로 설명한다.
따라서 운영 환경에서 별도로 설정한 Secret과 동일하게 취급해서는 안 된다.
4. URL의 Dot Segment를 이용한 페이지 접근 제어 우회
- 취약점: GHSA-9v7c-q64q-vv33
- 심각도: Moderate
- CVSS v3: 6.5
- 영향받는 버전: Nuxt 4.6.0 이상, 4.6.3 미만
- 수정 버전:
nuxt@4.6.3,@nuxt/nitro-server@4.6.3 - 공식 보안 권고: https://github.com/nuxt/nuxt/security/advisories/GHSA-9v7c-q64q-vv33
이번 릴리스에서 실제 운영 애플리케이션의 보안과 직접 연결되는 취약점이다.
문제의 원인은 Nuxt의 페이지 라우터와 Nitro의 서버 Middleware가 URL 경로를 서로 다르게 해석했다는 점이다.
URL에는 다음과 같은 경로 표현이 포함될 수 있다.
...%2e
.은 현재 경로를 의미한다.
..은 상위 경로를 나타낼 수 있다.
%2e는 점을 Percent Encoding으로 표현한 것이다.
예를 들어 다음 요청을 생각할 수 있다.
/%2e/admin
Nuxt의 페이지 라우터는 해당 경로를 정규화한 뒤 /admin 페이지로 해석할 수 있었다.
반면 Nitro의 server/middleware와 Route Rule은 정규화되지 않은 경로를 기준으로 요청을 검사할 수 있었다.
따라서 실제로는 관리자 페이지가 렌더링되지만, /admin을 보호하기 위해 작성한 경로 기반 검사가 적용되지 않는 문제가 발생했다.
예를 들어 Middleware에서 다음과 같은 정책을 사용했다고 가정해 보자.
event.path.startsWith("/admin")
이 조건은 일반적인 /admin 요청에는 일치한다.
하지만 인코딩된 Dot Segment가 포함된 경로에서는 기대한 방식으로 동작하지 않을 수 있었다.
그 결과 보호해야 하는 페이지가 인증되지 않은 사용자에게 렌더링될 가능성이 있었다.
서버의 Route Rule에도 영향을 줄 수 있었다.
예를 들어 다음과 같은 설정이다.
/admin접근 시 로그인 페이지로 Redirect- 특정 페이지에 보안 Header 추가
- 특정 페이지에 Content Security Policy 적용
이러한 규칙이 정규화되지 않은 경로에만 적용되면 실제 렌더링한 페이지에 해당 정책이 적용되지 않을 수 있었다.
이번 수정에서는 Dot Segment가 포함된 요청을 거부하고, Route Rule을 비교할 때 경로를 일관되게 처리하도록 변경했다.
다만 공식 권고는 영향받지 않는 범위도 명확히 구분한다.
server/api의 API Handler는 해당 취약점의 영향 대상이 아니다.server/routes의 Handler도 동일한 경로 우회의 영향을 받지 않는다.definePageMeta로 선언한 페이지 Middleware와 관련appMiddleware는 해결된 Route를 기준으로 검사하므로 영향 대상에서 제외된다.- Nuxt 3.x와 Nuxt 4.0.0~4.5.x는 해당 취약점의 영향 대상이 아니다.
따라서 Nuxt의 모든 Middleware가 우회됐다고 해석해서는 안 된다.
특히 서버 요청 경로를 직접 문자열로 비교하는 인증·인가 코드가 취약한 구성에 해당할 수 있다는 점이 중요하다.
5. Server Island 엔드포인트에서 Redirect Rule 누락
- 취약점: GHSA-2fxj-c3j7-rr69
- 심각도: Low
- 영향받는 버전: Nuxt 3.11.0 이상 및 4.6.3 미만
- 수정 버전: 4.6.3
- 공식 보안 권고: https://github.com/nuxt/nuxt/security/advisories/GHSA-2fxj-c3j7-rr69
Nuxt는 서버에서 특정 컴포넌트를 렌더링하는 Server Island 기능을 제공한다.
이를 이용하면 전체 페이지와 별도로 서버에서 렌더링한 결과를 가져올 수 있다.
하지만 .server.vue 페이지와 관련된 Island 엔드포인트에서 일부 Redirect Route Rule이 적용되지 않는 문제가 존재했다.
예를 들어 일반적인 페이지 접근은 /login으로 Redirect하도록 구성돼 있을 수 있다.
하지만 Server Island의 별도 엔드포인트를 통해 해당 페이지의 렌더링 결과를 가져오는 경우에는 Redirect 정책이 적용되지 않을 수 있었다.
공식 권고는 Redirect만을 접근 제어 수단으로 사용한 .server.vue 페이지를 주요 영향 대상으로 설명한다.
반면 실제 서버 또는 Route Middleware에서 별도로 인증을 검증하는 경우에는 해당 보호가 계속 적용될 수 있다.
따라서 이 취약점 역시 모든 Server Island의 인증이 무조건 우회된다는 의미는 아니다.
이번 수정에서는 Server Island 응답에도 관련 Redirect Route Rule을 적용하도록 변경했다.
보안 수정 외 성능 및 안정성 개선
Nuxt 4.6.3에는 보안 수정 외에도 여러 빌드 최적화가 포함됐다.
대표적인 변경은 다음과 같다.
| 영역 | 변경 내용 |
|---|---|
| Vite | 서버 빌드에서 불필요한 일반 Style Block 컴파일 생략 |
| Nitro·Rspack·webpack | Vue의 ESM Bundle과 관련 Cache 재사용 |
| Vite | fs.allow의 중첩 디렉터리 검사에서 발생하던 비효율 개선 |
| SSR | 내부 링크 렌더링 과정에서 불필요한 RouterLink 처리 감소 |
| Typed Routes | 필요하지 않은 Route 타입 생성 생략 |
useCookie | CookieStore 동기화와 Refresh 과정의 불필요한 재작성 수정 |
| Build Cache | shared/ 디렉터리의 변경을 Cache Hash에 반영 |
| Nitro | 클라이언트 연결 종료 시 관련 요청 중단 처리 개선 |
이러한 변경은 개발 서버의 반응성과 빌드 작업량을 줄이는 데 도움이 될 수 있다.
특히 파일 수가 많은 프로젝트에서는 디렉터리 검사나 불필요한 코드 생성이 누적돼 빌드 시간을 증가시킬 수 있다.
하지만 이번 공식 릴리스에는 이러한 최적화가 실제 빌드 시간을 몇 퍼센트 단축했는지에 관한 정량적인 Benchmark가 포함되지 않았다.
따라서 업데이트하면 모든 Nuxt 프로젝트의 빌드 시간이 특정 비율만큼 감소한다고 단정할 수는 없다.
이번 릴리스는 Nuxt의 개발 서버 보안 경계를 강화하고, 서버 렌더링과 Route Rule 사이의 경로 해석 불일치를 수정한 보안 중심 패치다.
2️⃣ 웹 플랫폼·브라우저
Firefox 159 정식 출시 — CSS Scroll-driven Animations 기본 활성화 및 Scoped Custom Element Registry 지원
- 발표일: 2026-10-27 — 정확한 게시 시각 미확인
- 버전: Firefox 159
- 안정화 단계: Stable
- 주요 변경: Scroll-driven Animations, Scoped Custom Element Registry, WebGL 확장, WebDriver BiDi 개선
- 원문: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/159
- 보안 권고: https://www.mozilla.org/en-US/security/advisories/mfsa2026-118/
Mozilla가 Firefox 159를 정식 출시하면서 CSS와 Web Components, WebGL, 브라우저 자동화 기능을 확장했다.
이번 릴리스에서 프론트엔드 개발에 직접적인 영향을 주는 변화는 두 가지다.
첫 번째는 CSS Scroll-driven Animations의 기본 활성화다.
두 번째는 Scoped Custom Element Registry 지원이다.
두 기능 모두 JavaScript 기반 구현에 의존하던 일부 작업을 브라우저의 기본 기능으로 처리할 수 있도록 한다.
CSS Scroll-driven Animations 기본 활성화
일반적인 CSS Animation은 시간의 흐름에 따라 진행된다.
예를 들어 다음과 같은 애니메이션을 생각할 수 있다.
요소가 1초 동안 왼쪽에서 오른쪽으로 이동한다.
이 경우 애니메이션의 진행 정도는 시간이 얼마나 지났는지에 따라 결정된다.
반면 Scroll-driven Animation에서는 시간이 아니라 사용자의 스크롤 위치를 애니메이션의 진행 기준으로 사용할 수 있다.
예를 들어 긴 기술 문서의 상단에 읽기 진행률을 표시한다고 가정해 보자.
사용자가 문서를 아래로 스크롤하면 상단의 Progress Bar가 오른쪽으로 늘어난다.
기존에는 JavaScript의 scroll 이벤트를 이용해 현재 스크롤 위치를 계산하고 CSS 스타일을 변경하는 방식이 사용됐다.
하지만 CSS Scroll-driven Animations를 사용하면 이러한 관계를 CSS에서 직접 정의할 수 있다.
대표적인 기능은 다음과 같다.
scroll()view()animation-timelinescroll-timelineview-timeline
scroll()은 스크롤 컨테이너의 진행 정도를 기준으로 Animation Timeline을 생성한다.
view()는 특정 요소가 Scrollport 안에 들어오고 나가는 과정을 기준으로 Timeline을 생성한다.
예를 들어 카드가 화면에 나타나는 동안 투명도를 변경하거나 위치를 이동시키는 효과를 구현할 수 있다.
이번 Firefox 159부터 해당 기능이 기본적으로 활성화됐다.
따라서 실험적인 브라우저 설정을 변경하지 않고 사용할 수 있다.
다만 Firefox에서 정식 지원이 시작됐다는 사실이 모든 브라우저가 동일한 기능을 지원한다는 의미는 아니다.
실제 서비스에서는 사용하는 Browser와 버전의 지원 여부를 확인해야 한다.
또한 스크롤 기반 애니메이션에서도 접근성을 고려해야 한다.
특히 큰 움직임이나 반복적인 시각 효과는 사용자에게 불편을 줄 수 있다.
필요한 경우 prefers-reduced-motion을 이용해 움직임 감소 설정을 반영할 수 있다.
Scoped Custom Element Registry 지원
Web Components에서는 Custom Element를 정의할 수 있다.
예를 들어 다음과 같은 태그를 사용하는 컴포넌트를 만들 수 있다.
<user-card>
Custom Element는 일반적으로 customElements.define()을 이용해 등록한다.
문제는 기존 등록 방식이 Document 전체에서 이름을 공유한다는 점이다.
예를 들어 서로 다른 두 라이브러리가 모두 user-card라는 이름의 Custom Element를 정의하려고 한다고 가정해 보자.
동일한 Registry에 같은 이름을 중복 등록할 수 없기 때문에 충돌이 발생할 수 있다.
이러한 문제는 대규모 웹 애플리케이션이나 Micro Frontend에서 특히 중요하다.
여러 팀이 서로 다른 버전의 컴포넌트를 사용하는 경우에도 같은 이름의 Custom Element가 존재할 수 있기 때문이다.
Scoped Custom Element Registry는 이러한 문제를 해결하기 위한 기능이다.
특정 Shadow Tree에 독립적인 Custom Element Registry를 연결할 수 있도록 한다.
따라서 서로 다른 Shadow Tree에서 같은 이름의 Custom Element를 각기 다른 구현에 연결할 수 있다.
대표적으로 다음 API가 추가됐다.
CustomElementRegistry()생성자Document.customElementRegistryElement.customElementRegistryShadowRoot.customElementRegistry
예를 들어 하나의 페이지에 서로 다른 버전의 Web Component 라이브러리가 포함돼 있다고 가정해 보자.
각 라이브러리가 자신의 Shadow Root에 별도의 Registry를 사용하면 이름 충돌을 줄일 수 있다.
그러나 Scoped Registry가 자동으로 JavaScript와 CSS, 네트워크 요청까지 격리하는 것은 아니다.
이 기능은 Custom Element 이름과 정의의 적용 범위를 분리하는 기능이다.
보안상 격리된 실행 환경이 필요하다면 iframe이나 다른 보안 경계를 검토해야 한다.
HTML Sanitizer API 내부 처리 개선
Firefox 159에서는 HTML Sanitizer API의 내부 처리 방식도 변경됐다.
대표적인 API는 다음과 같다.
Element.setHTML()
이 API는 HTML 문자열을 처리하면서 허용되지 않는 요소와 속성을 제거하는 데 사용할 수 있다.
기존 구현에서는 HTML을 먼저 파싱해 DOM을 구성한 뒤 정리하는 방식이 사용됐다.
새로운 구현에서는 HTML을 파싱하는 과정에서 허용하지 않는 요소와 속성을 제거하도록 변경됐다.
Mozilla에 따르면 최종 결과는 일반적으로 동일하다.
하지만 DOM의 세부 구조에는 차이가 있을 수 있다.
예를 들어 인접한 텍스트가 기존에는 여러 Text Node로 분리됐다면 새로운 구현에서는 하나의 Text Node로 결합될 수 있다.
따라서 DOM의 자식 노드 개수나 Text Node의 경계를 직접 검사하는 코드에서는 동작 차이가 나타날 수 있다.
이는 실제 화면에 표시되는 텍스트가 같더라도 내부 DOM 구조가 완전히 동일하다는 보장은 없다는 의미다.
WebGL 확장 지원
Firefox 159에서는 여러 WebGL 확장도 사용할 수 있게 됐다.
| 확장 | 주요 기능 |
|---|---|
EXT_clip_control | Clip Space와 화면 좌표의 매핑 방식 변경 |
EXT_texture_mirror_clamp_to_edge | 텍스처 좌표의 Mirror 및 Clamp 처리 |
EXT_texture_norm16 | 16비트 Normalized Texture와 Renderbuffer 형식 지원 |
EXT_clip_control은 Clip Space 좌표의 처리 방식을 조정할 수 있다.
예를 들어 WebGPU와 Direct3D에서 사용하는 좌표 관례에 가까운 설정을 사용할 수 있다.
또한 Reversed-Z 기법을 활용할 때 Depth Buffer의 정밀도를 개선하는 데 도움이 될 수 있다.
EXT_texture_norm16은 8비트보다 높은 정밀도의 텍스처 데이터를 처리하는 데 사용할 수 있다.
예를 들어 고도 데이터나 정밀한 이미지 데이터를 다루는 그래픽 애플리케이션에서 활용할 수 있다.
하지만 이러한 확장은 그래픽 드라이버와 하드웨어가 실제로 지원하는 경우에만 사용할 수 있다.
Firefox 159를 사용한다고 해서 모든 기기에서 모든 확장이 제공되는 것은 아니다.
따라서 애플리케이션에서는 필요한 확장이 실제로 지원되는지 확인해야 한다.
WebDriver BiDi 개선
브라우저 자동화와 관련해서도 변경이 있다.
Firefox 159는 WebDriver BiDi의 다음 명령을 지원한다.
emulation.setMediaFeaturesOverride
현재 지원하는 Media Feature는 다음과 같다.
prefers-color-scheme
이를 이용하면 브라우저 자동화 도구에서 Dark Mode와 Light Mode 관련 설정을 변경해 UI를 검사할 수 있다.
예를 들어 같은 페이지를 Light Mode와 Dark Mode에서 각각 렌더링하고 스타일을 비교할 수 있다.
다만 모든 CSS Media Feature를 변경할 수 있는 것은 아니다.
현재 지원 범위는 prefers-color-scheme으로 제한된다.
또한 기존의 다음 명령행 인자는 제거됐다.
--remote-allow-system-access
이제 시스템 접근을 활성화하려면 다음 환경 변수를 사용해야 한다.
MOZ_REMOTE_ALLOW_SYSTEM_ACCESS=1
따라서 Firefox 자동화 환경에서 기존 명령행 인자를 사용하고 있다면 설정 변경이 필요할 수 있다.
Firefox 159 보안 수정
Mozilla는 Firefox 159의 보안 권고도 공개했다.
공식 권고에는 High 심각도의 여러 취약점이 포함돼 있다.
대표적으로 다음 문제가 수정됐다.
| CVE | 문제 |
|---|---|
| CVE-2026-117860 | DOM Navigation의 Same-origin Policy 우회 |
| CVE-2026-117861 | DOM Navigation의 Sandbox Escape |
| CVE-2026-117862 | Networking 구성요소의 권한 상승 |
| CVE-2026-117864 | Form Manager의 Sandbox Escape |
| CVE-2026-117865 | JavaScript GC의 Use-after-free |
| CVE-2026-117866 | Canvas2D의 Use-after-free로 인한 권한 상승 |
이외에도 메모리 안전성 및 여러 브라우저 구성요소의 취약점이 수정됐다.
다만 공식 권고에 High 심각도의 취약점이 존재한다는 사실이 모든 취약점을 동일한 방법으로 악용할 수 있다는 의미는 아니다.
실제 악용 조건은 CVE마다 다르다.
또한 이번 브리핑에서 확인한 Mozilla 공식 권고는 수정 사항을 설명하지만, 모든 취약점이 실제 공격에 사용되고 있다는 증거를 제시하지는 않는다.
이번 Firefox 159는 스크롤 기반 CSS 애니메이션과 Web Components의 구성 범위를 확장하면서 그래픽 및 브라우저 자동화 기능을 개선하고 보안 취약점을 수정한 정식 릴리스다.
W3C, WebMCP Polyfill 오픈소스 프로젝트를 두 번째 공식 시범 사업으로 선정 — 브라우저의 네이티브 지원 이전에 상호운용성 실험
- 발표일: 2026-10-27 — 정확한 게시 시각 미확인
- 발표 주체: W3C
- 안정화 단계: Open Source Pilot, 실험 단계
- 관련 기술: WebMCP, Web Platform Tests, JavaScript Polyfill
- 원문: https://www.w3.org/blog/2026/w3c-launches-second-pilot-of-program-to-support-open-source-projects/
W3C가 WebMCP Polyfill 프로젝트를 새로운 오픈소스 지원 프로그램의 두 번째 시범 사업으로 선정했다고 발표했다.
이번 소식은 WebMCP의 정식 웹 표준 채택이나 브라우저의 네이티브 지원 발표가 아니다.
아직 개발 중인 WebMCP 규격을 여러 환경에서 실험할 수 있도록 Polyfill의 개발과 관리 체계를 지원한다는 내용이다.
WebMCP의 역할
WebMCP는 웹 애플리케이션이 AI 에이전트에 사용할 수 있는 기능을 구조화된 도구 형태로 제공하도록 하는 JavaScript 인터페이스다.
예를 들어 쇼핑몰에서 다음 도구를 제공할 수 있다.
- 상품 검색
- 장바구니에 상품 추가
- 주문 상태 조회
기존의 브라우저 자동화에서는 AI 에이전트가 화면의 HTML과 버튼 구조를 분석해 어떤 요소를 클릭해야 하는지 판단해야 할 수 있다.
반면 WebMCP에서는 애플리케이션이 사용할 수 있는 도구의 이름과 설명, 입력 Schema를 명시적으로 제공할 수 있다.
이렇게 하면 에이전트가 화면의 구조를 추측하는 대신 웹 애플리케이션이 제공한 기능을 호출하도록 구성할 수 있다.
하지만 현재 WebMCP는 W3C의 정식 Recommendation이 아니다.
규격이 개발 중인 Incubation 단계다.
따라서 실제 브라우저에서 사용할 수 있는 API와 동작은 앞으로 변경될 수 있다.
Polyfill이 필요한 이유
Polyfill은 브라우저가 아직 지원하지 않는 기능을 JavaScript 등으로 구현해 사용할 수 있도록 하는 호환성 계층이다.
예를 들어 새로운 Web API가 일부 브라우저에서만 제공된다고 가정해 보자.
해당 기능을 사용하는 애플리케이션은 지원하지 않는 브라우저에서도 비슷한 동작을 제공하기 위해 Polyfill을 사용할 수 있다.
WebMCP에서도 비슷한 문제가 존재한다.
브라우저마다 지원 여부가 다르고, 실험적인 구현과 API의 동작이 서로 달라질 수 있다.
W3C는 Polyfill을 통해 이러한 차이를 줄이고 개발자가 실제 애플리케이션에서 규격을 실험할 수 있도록 하는 것을 목표로 한다.
그러나 Polyfill이 존재한다고 해서 실제 브라우저의 모든 네이티브 기능을 동일하게 구현할 수 있는 것은 아니다.
브라우저의 보안 모델이나 AI 에이전트와의 연결 방식에 따라 Polyfill로 재현하기 어려운 기능이 존재할 수 있다.
프로젝트의 네 가지 초기 목표
W3C는 이번 프로젝트의 목표를 다음과 같이 공개했다.
첫 번째는 WebMCP Polyfill을 npm 패키지로 배포하는 것이다.
이를 통해 일반적인 JavaScript 프로젝트에서도 Polyfill을 설치하고 실험할 수 있도록 할 계획이다.
두 번째는 Lifecycle Event 지원을 개선하는 것이다.
Lifecycle Event는 도구의 등록이나 사용, 실행 상태와 관련된 이벤트 처리를 의미한다.
세 번째는 Declarative Support를 개선하는 것이다.
Declarative 방식은 JavaScript에서 모든 동작을 직접 호출하기보다 구조와 속성으로 의도를 표현하는 접근이다.
네 번째는 WebMCP의 규격 변화와 Web Platform Tests의 테스트 범위를 추적하는 것이다.
Web Platform Tests는 여러 브라우저와 구현에서 웹 플랫폼 기능의 동작을 검증하기 위한 공통 테스트 프로젝트다.
Polyfill 역시 규격이 변경될 때 해당 변경을 반영해야 한다.
따라서 이번 사업은 단순히 하나의 JavaScript 라이브러리를 만드는 작업보다 규격과 구현, 테스트 사이의 일관성을 관리하는 데 초점을 맞춘다.
새로운 Community Group
W3C는 이번 발표와 함께 W3C Open Source Program Community Group의 출범도 알렸다.
해당 그룹은 W3C 오픈소스 프로그램의 관리 체계와 향후 운영 방향을 논의할 예정이다.
W3C 회원이 아닌 개발자도 참여할 수 있다.
이러한 구조는 특정 기업이 Polyfill 구현을 독점적으로 관리하는 대신 여러 개발자가 공개적으로 참여할 수 있는 기반을 마련하려는 목적이다.
다만 Community Group이 만들어졌다는 사실만으로 WebMCP가 W3C 표준화 절차를 이미 완료했다는 의미는 아니다.
W3C는 WebMCP가 정식 표준화 절차로 이동하고, 브라우저의 네이티브 구현이 충분히 상호운용성을 제공하게 된다면 Polyfill의 역할이 점진적으로 줄어들 수 있다고 설명한다.
이전 WebMCP 발표와의 차이
10월 21일에는 Cloudflare와 Commerce.com이 WebMCP를 많은 쇼핑몰에 적용하는 구조를 공개했다.
그 발표는 특정 상용 플랫폼에서 WebMCP를 제공하는 구현 사례였다.
반면 이번 W3C 발표는 여러 구현 사이의 상호운용성을 높이기 위한 공개 Polyfill 프로젝트의 개발 지원에 관한 것이다.
따라서 동일한 뉴스를 다시 소개하는 것이 아니다.
이번 발표에서는 브라우저 기능의 안정화 시점이나 실제 성능 수치가 제공되지 않았다.
아직 초기 단계의 기술을 여러 환경에서 검증할 수 있도록 지원하는 프로젝트이기 때문이다.
3️⃣ 백엔드·인프라
Cloudflare Workflows, 실행 지역 제한 기능 출시 — EU·미국·FedRAMP 지역에 상태 저장과 실행 위치 고정
- 발표일: 2026-10-27 — 정확한 게시 시각 미확인
- 적용 대상: Cloudflare Workflows, Workers
- 지원 지역:
eu,us,fedramp - 필요 버전: Wrangler 4.152.0 이상
- 원문: https://developers.cloudflare.com/changelog/post/2026-10-27-workflow-jurisdictions/
- 공식 문서: https://developers.cloudflare.com/workflows/reference/data-location/
Cloudflare가 Workflows의 실행 위치와 상태 저장 지역을 지정된 Jurisdiction으로 제한하는 기능을 추가했다.
Workflows는 여러 단계로 구성된 백엔드 작업을 실행하는 기능이다.
예를 들어 사용자가 동영상 파일을 업로드하면 다음 작업이 수행될 수 있다.
- 업로드된 파일 확인
- 동영상 변환 작업 요청
- 변환 완료 대기
- 썸네일 생성
- 데이터베이스 갱신
- 사용자에게 완료 알림 전송
이러한 작업은 하나의 HTTP 요청 안에서 모두 처리되지 않을 수 있다.
일부 단계는 오래 실행되거나 외부 API의 결과를 기다려야 할 수 있다.
Cloudflare Workflows는 이러한 단계를 지속적인 작업으로 관리할 수 있도록 한다.
이번 업데이트는 해당 작업을 어느 지역에서 실행하고 상태를 저장할 것인지 명시적으로 결정할 수 있도록 확장했다.
지원하는 Jurisdiction
현재 지원하는 값은 다음과 같다.
| 값 | 실행 및 저장 지역 |
|---|---|
eu | 유럽연합 |
us | 미국 |
fedramp | FedRAMP Moderate 데이터센터 |
예를 들어 유럽연합의 데이터 지역 정책을 적용해야 하는 작업이라면 eu를 지정할 수 있다.
이 경우 Cloudflare는 해당 Workflow의 인스턴스가 지정한 Jurisdiction 안에서 실행되고 관련 데이터를 저장하도록 제한한다.
이는 일반적인 전 세계 분산 실행과 다른 방식이다.
일반적인 엣지 플랫폼에서는 사용자의 위치에 가까운 실행 환경을 선택해 지연 시간을 줄이는 것이 중요할 수 있다.
반면 데이터 지역 제한이 필요한 서비스에서는 처리 속도보다 특정 지역 안에서 데이터를 처리하는 것이 더 중요할 수 있다.
이번 기능은 이러한 요구사항을 반영한다.
설정 방법
Wrangler 설정의 workflows Binding에 jurisdiction을 지정할 수 있다.
예를 들어 JSON 설정에서는 다음과 같은 값을 사용한다.
"jurisdiction": "eu"
TOML 설정에서도 동일한 항목을 사용할 수 있다.
또한 Workflow를 exports에 선언하는 방식에서도 지역을 설정할 수 있다.
따라서 별도의 지역별 Worker 코드를 새롭게 작성하지 않고 기존 Workflow의 설정에서 실행 지역을 지정할 수 있다.
하지만 설정을 추가했다고 해서 애플리케이션 전체의 모든 데이터 이동이 해당 지역으로 제한되는 것은 아니다.
예를 들어 Workflow가 다른 지역의 외부 API를 호출한다면 해당 API의 데이터 처리 위치는 별도의 문제다.
또한 외부 데이터베이스나 Object Storage의 데이터 보관 정책도 따로 확인해야 한다.
이번 기능은 Cloudflare Workflows 인스턴스의 실행과 관련 데이터 저장 위치를 제한하는 기능이다.
전체 시스템의 모든 서비스에 동일한 지역 제한을 자동으로 적용하는 것은 아니다.
생성 이후 Jurisdiction 변경 불가
이번 기능에는 중요한 제한사항이 있다.
Workflow의 Jurisdiction은 Workflow를 처음 생성할 때 결정하며 이후 변경할 수 없다.
예를 들어 기존 Workflow가 미국 지역에 생성됐다고 가정해 보자.
이후 설정 파일에서 다음 값으로 변경한다.
"jurisdiction": "eu"
이 경우 Cloudflare가 기존 Workflow를 자동으로 EU 지역으로 이전하지 않는다.
대신 배포 과정에서 오류가 발생한다.
영향받는 명령에는 다음이 포함된다.
wrangler deploywrangler versions upload
Cloudflare는 Worker 파일을 업로드하기 전에 Jurisdiction의 불일치를 검사한다.
따라서 이미 생성한 Workflow의 지역 설정이 다른 경우에는 배포 자체가 중단된다.
이는 기존 데이터와 실행 상태를 예기치 않게 다른 지역으로 이동시키지 않기 위한 제약이다.
실제로 Workflow를 다른 지역으로 이전하려면 새로운 Workflow를 생성하고 기존 작업의 상태와 데이터를 어떻게 처리할지 별도로 설계해야 할 수 있다.
안정화 및 적용 범위
이번 기능은 Wrangler 4.152.0 이상에서 사용할 수 있다.
따라서 오래된 Wrangler를 사용하는 프로젝트에서는 jurisdiction 설정을 인식하지 못할 수 있다.
또한 이번 발표에는 지역 제한을 적용했을 때 실행 지연 시간이나 비용이 얼마나 변경되는지에 관한 Benchmark가 포함되지 않았다.
따라서 지역을 고정해도 모든 사용자에게 동일한 응답 시간이 제공된다고 단정할 수 없다.
이번 업데이트는 장시간 실행되는 서버리스 작업의 실행 위치와 상태 저장 지역을 명시적으로 제한할 수 있도록 한 데이터 지역 관리 기능이다.
Google Cloud AlloyDB, SQL 내부에서 구조화된 데이터 추출·텍스트 분류 지원 — ai.extract·ai.classify Preview 공개
- 발표일: 2026-10-27 — 정확한 게시 시각 미확인
- 발표 주체: Google Cloud
- 적용 대상: AlloyDB for PostgreSQL
- 안정화 단계: Preview
- 신규 함수:
ai.extract,ai.classify - 원문: https://docs.cloud.google.com/release-notes/
- 데이터 추출 문서: https://docs.cloud.google.com/alloydb/docs/ai/extract-structured-data
- 텍스트 분류 문서: https://docs.cloud.google.com/alloydb/docs/ai/classify-text
Google Cloud가 AlloyDB의 SQL Query 안에서 AI 모델을 이용해 비정형 텍스트를 구조화하거나 분류하는 기능을 Preview로 공개했다.
이번 업데이트는 데이터베이스에 AI 관련 데이터를 단순히 저장하는 것과 다르다.
SQL Query를 실행하는 과정에서 직접 AI 모델을 호출해 데이터 추출과 분류 작업을 수행할 수 있도록 한다.
예를 들어 고객 문의를 관리하는 시스템을 생각해 보자.
데이터베이스에는 사용자가 작성한 문의 내용이 문자열로 저장돼 있을 수 있다.
하지만 실제 고객지원 시스템에서는 다음 정보가 필요할 수 있다.
- 문의 유형
- 주문번호
- 고객이 원하는 작업
- 담당 부서
- 긴급도
기존에는 이러한 정보를 추출하기 위해 별도의 백엔드 프로그램을 실행해야 할 수 있었다.
데이터베이스에서 텍스트를 조회한다.
AI 모델 API를 호출한다.
결과를 다시 데이터베이스에 저장한다.
이번 기능은 이러한 작업의 일부를 SQL에서 직접 수행할 수 있도록 한다.
ai.extract: 비정형 텍스트에서 구조화된 데이터 추출
첫 번째 함수는 다음과 같다.
ai.extract()
이 함수는 텍스트와 출력 구조를 전달받아 필요한 데이터를 추출한다.
예를 들어 영업 상담 기록에 다음 정보가 포함돼 있다고 가정해 보자.
- 고객 이름
- 회사 이름
- 직책
- 제품 요구사항
개발자는 output_schema를 이용해 추출할 필드를 정의할 수 있다.
대표적인 SQL 형태는 다음과 같다.
SELECT ai.extract(input => raw_transcript, output_schema => '...')
output_schema에는 JSON 형태의 필드 구조를 지정할 수 있다.
예를 들어 다음 데이터를 추출하도록 구성할 수 있다.
contact_namecompany_namejob_title
AlloyDB는 해당 텍스트를 AI 모델에 전달하고 지정된 구조의 결과를 반환할 수 있다.
또한 배열 형태의 데이터도 추출할 수 있다.
예를 들어 하나의 상담 기록에 여러 기술 이름이 등장한다면 이를 배열로 반환하도록 구성할 수 있다.
하지만 Schema에 맞는 데이터가 반환됐다는 사실이 추출한 내용까지 올바르다는 보장은 아니다.
모델이 실제 원문에 존재하지 않는 정보를 생성하거나 일부 정보를 잘못 해석할 수 있기 때문이다.
따라서 주문번호나 결제 금액처럼 중요한 데이터에서는 추가적인 유효성 검사가 필요하다.
ai.classify: 텍스트를 미리 정의한 유형으로 분류
두 번째 함수는 다음과 같다.
ai.classify()
이 함수는 텍스트를 지정된 카테고리로 분류한다.
예를 들어 고객 문의를 다음 세 가지로 분류할 수 있다.
- 배송
- 결제
- 환불
대표적인 SQL 형태는 다음과 같다.
SELECT ai.classify(input => inquiry, categories => ARRAY['shipping', 'payment', 'refund'])
기본적으로 하나의 카테고리를 선택하도록 구성할 수 있다.
또한 다음 값을 이용해 여러 카테고리를 반환하도록 설정할 수도 있다.
output_mode => 'multi'
이러한 방식은 하나의 문서에 여러 주제가 포함된 상황에서 활용할 수 있다.
예를 들어 기술 관련 뉴스가 보안과 AI 두 분야에 동시에 해당할 수 있다.
또한 각 카테고리에 설명을 제공할 수도 있다.
단순히 카테고리 이름만 전달하는 것보다 어떤 경우에 해당 카테고리를 선택해야 하는지 명확하게 설명할 수 있다.
examples를 이용해 입력과 기대 출력의 예시를 제공하는 방법도 지원한다.
이는 Few-shot 방식에 해당한다.
하지만 카테고리 설명이나 예시를 제공했다고 해서 모델의 분류 결과가 항상 정확한 것은 아니다.
실제 데이터에 맞는 분류 정확도는 별도로 평가해야 한다.
대량 데이터 처리를 위한 세 가지 방식
AlloyDB는 여러 행의 데이터를 처리하는 데 세 가지 방식을 제공한다.
| 처리 방식 | 특징 |
|---|---|
| Scalar Function | 하나의 텍스트를 처리 |
| Array-based Batching | 여러 입력을 배열로 묶어 처리 |
| Cursor-based Processing | 대량 데이터를 Cursor 단위로 순차 처리 |
예를 들어 고객 문의가 10만 건 존재한다고 가정해 보자.
각 행에 대해 별도의 모델 호출을 수행하면 전체 작업에 많은 시간이 필요할 수 있다.
이때 Batch를 이용해 여러 입력을 묶어 처리할 수 있다.
ai.classify의 Array 기반 함수에서는 batch_size를 지정할 수 있다.
기본 Batch 크기는 10이다.
ai.extract도 여러 입력을 배열로 전달할 수 있다.
또한 Cursor 기반 함수는 전체 데이터를 한 번에 메모리에 올리지 않고 일정한 단위로 처리할 수 있도록 한다.
AlloyDB는 Smart Batching 기능도 제공한다.
이를 활성화하면 여러 Scalar AI 함수 호출을 내부적으로 묶어 처리할 수 있다.
관련 설정은 다음과 같다.
google_ml_integration.enable_ai_function_acceleration
그러나 Smart Batching이 모든 Query에서 항상 더 빠른 결과를 보장하는 것은 아니다.
실제 성능은 입력 크기와 Batch 구성, 모델 호출 지연 시간 등에 영향을 받는다.
이번 발표에는 모든 데이터 규모에서의 성능을 비교한 독립적인 Benchmark가 포함되지 않았다.
Preview 사용 조건
이번 기능은 Preview 단계다.
따라서 기본 설정만으로 모든 AlloyDB 인스턴스에서 사용할 수 있는 것은 아니다.
공식 문서는 다음 조건을 명시한다.
- PostgreSQL 18 이상
google_ml_integration1.6.1 이상- Preview 관련 기능 활성화
필요한 설정에는 다음 항목이 포함된다.
google_ml_integration.enable_ai_query_enginegoogle_ml_integration.enable_preview_ai_functions
이러한 설정은 기본적으로 비활성화돼 있다.
따라서 필요한 기능을 활성화한 뒤 사용할 수 있다.
기본 모델은 공식 문서에서 다음과 같이 안내한다.
gemini-3.5-flash-lite
다만 다른 지원 모델을 지정할 수도 있다.
실제 모델 지원 범위와 비용은 모델 엔드포인트 구성에 따라 달라질 수 있다.
기존 AI 함수의 파라미터 변경
이번 업데이트에는 새 함수 추가 외에도 기존 AI Query Engine 함수의 변경이 포함됐다.
영향받는 함수는 다음과 같다.
ai.analyze_sentimentai.summarizeai.agg_summarize
대표적인 변경은 파라미터 이름이다.
| 기존 이름 | 새로운 이름 |
|---|---|
prompt | input |
prompts | inputs |
또한 ai.summarize와 ai.agg_summarize에는 다음 선택 인자가 추가됐다.
additional_instructions
이를 이용해 요약의 길이와 형식, 톤 등에 관한 추가 지침을 제공할 수 있다.
반면 Cursor 기반의 ai.analyze_sentiment와 ai.summarize에서는 기존 prompt 인자가 제거됐다.
따라서 기존 Preview API를 사용하던 프로젝트에서는 함수 호출 형식의 변경이 필요할 수 있다.
이번 업데이트는 기존 관계형 데이터베이스에서 AI 기반 텍스트 처리 기능을 직접 실행할 수 있도록 SQL의 활용 범위를 확장한 Preview 기능이다.
다만 AI 모델 호출을 포함하는 Query는 일반적인 문자열 처리 Query와 지연 시간 및 비용 특성이 다르므로 실제 운영 환경의 요구사항에 맞춰 검증해야 한다.
Google Cloud DNS, 2027년 1월부터 CNAME 탐색 순서 변경 예고 — Public·Private DNS 간 이름 해석 결과 달라질 수 있음
- 발표일: 2026-10-27 — 정확한 게시 시각 미확인
- 변경 적용 예정일: 2027-01-05
- 적용 대상: Google Cloud DNS, VPC DNS Resolution
- 변경 유형: 향후 적용될 호환성 변경 예고
- 원문: https://docs.cloud.google.com/release-notes/
Google Cloud가 2027년 1월 5일부터 CNAME을 따라 DNS 이름을 해석하는 방식을 변경할 예정이라고 발표했다.
이번 변경은 아직 적용된 기능이 아니다.
따라서 2026년 10월 28일 현재 모든 DNS 요청의 동작이 변경됐다고 해석해서는 안 된다.
하지만 Public DNS와 Private DNS를 함께 사용하는 서비스에서는 실제 연결 대상이 달라질 수 있으므로 사전에 확인해야 할 변경이다.
CNAME의 역할
DNS는 도메인 이름을 IP 주소 등의 정보로 변환하는 시스템이다.
예를 들어 사용자가 다음 주소에 접근한다고 가정해 보자.
api.example.com
이 도메인에는 직접 IP 주소를 지정할 수도 있다.
하지만 다른 도메인의 별칭으로 지정할 수도 있다.
이를 CNAME이라고 한다.
예를 들어 다음과 같은 구성이 가능하다.
api.example.com → service.example.net
DNS Resolver는 CNAME을 확인한 뒤 실제 대상 도메인의 주소를 다시 조회한다.
이러한 과정을 CNAME Chasing이라고 한다.
문제는 클라우드 환경에서 Public DNS와 Private DNS가 함께 존재할 수 있다는 점이다.
Public DNS와 Private DNS
Public DNS는 일반적인 인터넷에서 조회할 수 있는 DNS 정보를 제공한다.
반면 Private DNS는 특정 VPC나 내부 네트워크에서만 사용할 수 있는 이름을 제공할 수 있다.
예를 들어 다음과 같은 구성이 존재할 수 있다.
- 외부 사용자용 API:
api.example.com - 내부 서비스용 API:
internal.example.com
하지만 같은 이름이 Public Zone과 Private Zone 양쪽에 존재할 수도 있다.
이 경우 DNS Resolver가 어떤 Zone을 우선 확인하는지에 따라 결과가 달라질 수 있다.
Google Cloud는 이번 변경을 통해 CNAME 대상의 다음 DNS 조회를 VPC의 전체 이름 해석 순서에 따라 수행하도록 변경할 예정이다.
기존 동작과 변경 이후 동작
공식 문서에서는 세 가지 상황을 구분한다.
| CNAME 응답 출처 | 기존 동작 | 변경 이후 |
|---|---|---|
| Public Zone | 주로 Public DNS와 내부 DNS를 조회 | VPC의 전체 DNS 해석 순서 적용 |
| Private Zone | 허용된 Private Zone을 중심으로 조회 | 필요하면 Public Zone까지 탐색 |
| Response Policy | 일부 경우 CNAME을 추가로 따라가지 않음 | VPC 해석 순서에 따라 추가 조회 |
예를 들어 Public DNS에 다음 CNAME이 있다고 가정해 보자.
public.example.com → internal.example.com
기존에는 대상 도메인을 Public DNS에서만 조회해 결과를 찾지 못했을 수 있다.
하지만 변경 이후에는 VPC에 연결된 Private Zone에서 해당 이름을 찾을 가능성이 있다.
그 결과 기존에는 NXDOMAIN이 반환되던 요청이 내부 IP 주소를 반환할 수 있다.
반대 상황도 가능하다.
Private Zone에 존재하는 CNAME의 대상이 Public Zone에서 발견될 수 있다.
따라서 기존에는 실패하던 이름 해석이 성공하거나 예상과 다른 IP 주소를 반환할 수 있다.
이는 DNS 서버가 고장 났다는 의미가 아니라 이름 해석의 탐색 순서가 변경되면서 발생하는 동작 차이다.
기존 스크립트와 모니터링의 영향
Google Cloud는 실제 적용 전에 다음 도구를 이용해 CNAME 경로를 확인하도록 안내한다.
dignslookup
특히 Public Zone과 Private Zone에 이름이 겹치는 경우를 확인할 필요가 있다.
또한 CNAME Chain에 포함된 레코드의 TTL을 일관되게 설정하는 것이 도움이 될 수 있다.
TTL(Time To Live)은 DNS 조회 결과를 캐시에 유지할 수 있는 시간을 나타낸다.
CNAME Chain의 각 레코드가 서로 다른 TTL을 사용하면 일부 데이터가 먼저 갱신되고 다른 데이터는 캐시에 남을 수 있다.
이러한 상황에서는 DNS 변경 이후의 동작을 분석하기 어려워질 수 있다.
DNS ANY Query 응답 방식도 변경 예정
Google Cloud는 같은 날짜부터 Public Authoritative Zone의 ANY Query 응답 방식도 변경할 예정이다.
QTYPE=ANY는 특정 이름에 관한 여러 종류의 DNS 레코드를 요청하는 방식이다.
하지만 변경 이후에는 전체 레코드 목록 대신 해당 이름에 존재하는 레코드 중 하나를 반환하도록 바뀐다.
예를 들어 다음 명령을 사용하는 경우다.
dig example.com ANY
기존에는 여러 종류의 레코드가 표시됐을 수 있다.
하지만 변경 이후에는 전체 레코드 목록을 얻는 용도로 사용할 수 없다.
일반적인 브라우저와 HTTP 클라이언트는 필요한 레코드 유형을 직접 요청하므로 영향을 받지 않는다.
반면 다음 시스템에는 영향이 있을 수 있다.
- 오래된 DNS 모니터링 도구
- 모든 레코드를 ANY Query로 조회하는 스크립트
- DNS 정보를 분석하는 내부 자동화
- 일부 장애 진단 명령
전체 레코드 목록이 필요한 경우에는 Cloud DNS API나 CLI를 사용하도록 안내한다.
이번 발표는 DNS의 실제 변경이 적용되기 전에 Public·Private Zone의 해석 차이와 기존 자동화의 호환성 문제를 미리 공지한 것이다.
4️⃣ 개발 도구 및 보안
Cloudflare Access, HTML·Liquid 기반 인증·접근 거부 페이지 커스터마이징 지원 — 정책 결과를 사용자에게 설명 가능
- 발표일: 2026-10-27 — 정확한 게시 시각 미확인
- 적용 대상: Cloudflare Access, Cloudflare One
- 지원 방식: HTML, Liquid Template
- 원문: https://developers.cloudflare.com/changelog/post/2026-10-27-access-custom-pages/
- 공식 문서: https://developers.cloudflare.com/cloudflare-one/reusable-components/custom-pages/access-custom-pages/
Cloudflare가 Access에서 사용자에게 표시하는 인증과 접근 거부 화면을 HTML 및 Liquid Template으로 직접 구성할 수 있도록 기능을 확장했다.
Cloudflare Access는 애플리케이션에 접근할 수 있는 사용자를 인증하고 접근 정책을 적용하는 기능이다.
예를 들어 회사 내부의 관리자 페이지를 외부에 제공하되, 특정 조직에 소속된 사용자만 접근하도록 제한할 수 있다.
이 경우 사용자에게 표시되는 화면에는 여러 종류가 있다.
- 로그인 화면
- 인증은 완료했지만 접근 정책을 충족하지 못한 화면
- 접근이 금지된 화면
- CLI 인증 승인 화면
기존에는 이러한 화면에 적용할 수 있는 커스터마이징 범위가 제한적이었다.
이번 업데이트는 각 화면의 HTML과 CSS, 사용자에게 표시할 설명 문구를 더 세밀하게 제어할 수 있도록 한다.
Liquid Template의 역할
Liquid는 템플릿 안에 변수와 조건문을 사용할 수 있도록 하는 템플릿 언어다.
예를 들어 Access에서 다음 정보를 제공할 수 있다.
- 애플리케이션 이름
- 사용자 이메일
- Ray ID
- 일부 정책 평가 정보
이러한 값을 이용해 사용자에게 더 구체적인 안내를 표시할 수 있다.
예를 들어 일반적인 접근 거부 화면에서는 다음 메시지만 표시할 수 있다.
Access denied
하지만 사용자별 정보를 활용하면 현재 어떤 계정으로 로그인했는지 안내할 수 있다.
또한 관리자에게 문의할 때 필요한 Ray ID를 표시할 수도 있다.
Ray ID는 Cloudflare에서 요청을 식별하는 데 사용할 수 있는 값이다.
이를 이용하면 운영자가 특정 요청과 관련된 로그를 찾는 데 도움이 될 수 있다.
템플릿별 필수 요소
Access의 인증과 승인 기능은 Cloudflare가 직접 관리한다.
따라서 개발자는 템플릿의 HTML을 완전히 자유롭게 변경할 수 있는 것이 아니다.
특정 화면에는 Cloudflare가 요구하는 필수 요소를 포함해야 한다.
예를 들어 CLI 인증 승인 화면에는 다음 요소가 필요하다.
<cf-access-cli-approval></cf-access-cli-approval>
이 요소는 실제 승인 UI와 연결된다.
공식 문서에 따르면 해당 요소는 정확히 하나 존재해야 한다.
또한 조건문이나 반복문 안에 배치해 실제 렌더링 시 사라지도록 구성해서는 안 된다.
이는 사용자에게 표시하는 화면을 변경하더라도 실제 인증과 승인 과정의 보안 구조를 유지하기 위한 제한이다.
JavaScript와 인증 Form 제한
이번 기능은 HTML 커스터마이징을 지원하지만 다음 동작은 허용하지 않는다.
- 사용자가 작성한 JavaScript 실행
- Inline Event Handler
- 임의의 인증 Form
- Cloudflare가 제공하는 승인 버튼을 대체하는 사용자 정의 버튼
또한 일부 Liquid 기능도 제한된다.
사용할 수 없는 기능에는 다음 항목이 포함된다.
includerenderlayoutechoraw
HTML과 CSS에는 Sanitization이 적용된다.
외부 이미지와 Font 역시 Content Security Policy의 제한을 받는다.
따라서 로그인 화면을 일반적인 웹페이지처럼 완전히 자유롭게 실행하는 구조가 아니다.
사용자에게 표시하는 정보를 변경하되 실제 인증과 승인 처리는 Cloudflare가 관리하도록 분리한 방식이다.
정책 정보 노출에 관한 제한
공식 문서는 접근 거부 화면에 너무 많은 내부 정책 정보를 표시하지 않도록 주의하라고 안내한다.
예를 들어 특정 사용자에게 접근 권한이 없다는 사실을 알려주는 것은 유용할 수 있다.
하지만 내부 조직의 모든 그룹 이름이나 정책 조건, 민감한 Claim 값을 그대로 노출하면 보안상 문제가 발생할 수 있다.
따라서 어떤 정보를 사용자에게 표시할지 결정해야 한다.
Liquid 변수는 출력 과정에서 HTML Escaping이 적용된다.
존재하지 않는 변수는 빈 문자열로 렌더링된다.
하지만 Escaping이 적용된다는 사실과 민감한 정보를 노출해도 안전하다는 사실은 다르다.
접근 거부 이유를 구체적으로 설명하더라도 내부 시스템의 세부 정책을 지나치게 공개하지 않도록 설계해야 한다.
적용 범위
템플릿은 Cloudflare One Dashboard에서 생성할 수 있다.
다음 경로를 사용한다.
Reusable components > Custom pages
에디터에서 HTML과 Liquid 구문을 검증할 수 있다.
이후 특정 애플리케이션에 연결하거나 계정 전체의 기본값으로 설정할 수 있다.
따라서 여러 애플리케이션에서 동일한 디자인을 사용하면서 일부 애플리케이션에만 별도의 안내 문구를 적용할 수 있다.
이번 업데이트는 인증 정책 자체를 변경하지 않고 사용자에게 표시되는 인증·접근 거부 경험을 개선할 수 있도록 한 관리 기능이다.
Vercel Observability, AI Bot 트래픽 분석 지원 — AI 크롤러와 사용자 요청 기반 검색 트래픽 구분
- 발표일: 2026-10-27 — 정확한 게시 시각 미확인
- 적용 대상: Vercel Observability
- CLI 조회 조건: Observability Plus
- 원문: https://vercel.com/changelog/ai-traffic-insights-now-available-in-vercel-observability
Vercel이 웹사이트에 접근하는 AI Bot의 요청을 분석할 수 있는 AI Traffic Insights 기능을 추가했다.
웹사이트의 트래픽 분석은 전통적으로 실제 사용자의 브라우저 요청을 중심으로 이루어졌다.
예를 들어 Google Analytics나 일반적인 서버 로그를 이용해 다음 정보를 확인할 수 있다.
- 페이지 조회 수
- 방문자 수
- 접속 국가
- 유입 경로
- 오류 발생률
하지만 AI 검색과 AI 에이전트의 사용이 증가하면서 실제 사람의 브라우저가 아닌 자동화된 시스템의 요청도 중요해지고 있다.
예를 들어 다음 두 상황을 생각할 수 있다.
첫 번째는 AI 크롤러가 모델 학습이나 검색 색인을 위해 웹사이트의 여러 페이지를 가져오는 경우다.
두 번째는 사용자가 AI 비서에게 특정 질문을 했고, 해당 비서가 답변을 생성하기 위해 웹페이지를 가져오는 경우다.
두 상황은 모두 AI 관련 요청이지만 목적은 다르다.
이번 기능은 이러한 요청을 구분해 웹사이트의 실제 AI 접근 패턴을 분석할 수 있도록 한다.
제공하는 주요 지표
AI Traffic Insights에서는 다음 정보를 확인할 수 있다.
| 지표 | 확인할 수 있는 정보 |
|---|---|
| Verified AI Bot Requests | 확인된 AI Bot별 요청 수 |
| Most-crawled Pages | AI 크롤러가 자주 가져오는 페이지 |
| Assistant Retrievals | 사용자 요청이나 검색에 의해 AI 비서가 가져온 페이지 |
| Markdown Requests | Markdown 형식으로 요청된 페이지 |
| Errors | AI Bot 요청에서 오류가 발생한 페이지 |
예를 들어 기술 블로그를 운영한다고 가정해 보자.
특정 글은 일반 사용자의 방문자가 많지 않더라도 AI 검색 시스템에서 자주 가져올 수 있다.
반대로 다른 글은 실제 방문자가 많지만 AI Bot의 접근은 적을 수 있다.
이러한 차이를 확인하면 기존의 페이지 조회 통계만으로는 파악하기 어려운 요청 패턴을 분석할 수 있다.
하지만 AI Bot의 요청 수가 많다는 사실이 해당 페이지의 내용이 실제 AI 답변에 인용됐다는 의미는 아니다.
Bot이 페이지를 가져왔다는 사실과 모델이 해당 내용을 학습하거나 최종 사용자에게 제공했다는 사실은 구분해야 한다.
Verified AI Bot의 의미
Vercel은 확인된 AI Bot을 기준으로 요청을 집계한다.
이는 단순히 HTTP User-Agent 문자열에 특정 AI 서비스 이름이 포함됐는지만 확인하는 방식보다 신뢰할 수 있는 분류를 제공하려는 목적이다.
그러나 확인된 AI Bot의 트래픽이 전체 AI 관련 요청을 완전히 나타낸다고 보장할 수는 없다.
모든 자동화된 요청이 알려진 Bot으로 식별되는 것은 아니기 때문이다.
또한 일반적인 브라우저와 비슷한 형태로 동작하는 에이전트는 다른 유형의 트래픽으로 분류될 가능성이 있다.
따라서 AI Traffic Insights는 Vercel이 확인할 수 있는 AI Bot 요청의 관측 결과로 이해해야 한다.
CLI에서 분석
Vercel Dashboard에서는 다음 경로를 사용할 수 있다.
Observability > AI Traffic
또한 Vercel CLI에서 관련 Metric을 조회할 수 있다.
대표적인 명령은 다음과 같다.
vc metrics vercel.ai_traffic.count --group-by botName
이 명령은 AI Bot 이름별 요청 수를 조회하는 데 사용할 수 있다.
따라서 자동화된 보고서나 자체 분석 도구와 연결할 수 있다.
하지만 CLI를 이용한 Metric 조회에는 Observability Plus가 필요하다.
Dashboard에서 정보를 확인할 수 있다는 사실과 모든 CLI 기능을 무료로 사용할 수 있다는 사실은 구분해야 한다.
적용 범위와 제한사항
이번 기능은 검색 엔진 최적화 규칙을 자동으로 변경하지 않는다.
또한 robots.txt를 수정하거나 AI 크롤러의 접근을 차단하는 기능도 아니다.
실제로 발생한 요청을 분석하는 Observability 기능이다.
AI Bot의 접근을 제한하려면 별도의 Bot Management나 Firewall, 크롤러 정책 등이 필요할 수 있다.
이번 발표에는 AI Traffic Insights를 활성화했을 때 응답 시간이 얼마나 증가하는지 또는 데이터 수집 정확도가 얼마나 개선되는지에 관한 독립적인 Benchmark가 포함되지 않았다.
AI 검색과 에이전트의 웹사이트 접근을 실제 요청 로그 기반으로 분석할 수 있도록 Observability의 범위를 확장한 업데이트다.
Vercel AI SDK HarnessAgent, 모든 Adapter에서 이미지 입력 지원 — 텍스트와 스크린샷을 하나의 메시지로 전달
- 발표일: 2026-10-27 — 정확한 게시 시각 미확인
- 적용 대상: Vercel AI SDK, HarnessAgent
- 지원 범위: 모든 기존 Harness Adapter
- 원문: https://vercel.com/changelog/harness-agent-image-inputs
Vercel이 AI SDK의 HarnessAgent에서 이미지와 텍스트를 함께 전달할 수 있도록 모든 Harness Adapter의 입력 기능을 확장했다.
AI 코딩 에이전트는 기존에 텍스트를 중심으로 작업하는 경우가 많았다.
예를 들어 사용자가 다음과 같이 요청할 수 있다.
이 버튼의 오류를 수정해 줘.
하지만 실제 프론트엔드 문제를 설명할 때는 텍스트보다 이미지가 유용한 경우가 많다.
예를 들어 사용자가 브라우저 화면의 스크린샷을 제공하면서 특정 레이아웃을 구현하거나 수정하도록 요청할 수 있다.
이때 에이전트가 이미지와 텍스트를 함께 처리할 수 있어야 한다.
이번 업데이트는 HarnessAgent의 표준 메시지 형식 안에서 이미지 입력을 지원하도록 변경했다.
표준 메시지의 Content 배열
새로운 방식에서는 하나의 User Message 안에 여러 종류의 Content를 포함할 수 있다.
대표적으로 다음 두 종류가 있다.
type: "text"type: "file"
예를 들어 사용자의 요청에는 다음 두 정보가 함께 포함될 수 있다.
첫 번째는 텍스트다.
이 스크린샷과 동일한 UI를 구현해 줘.
두 번째는 이미지 파일이다.
이미지에는 다음 정보가 포함될 수 있다.
mediaTypedata
예를 들어 PNG 파일은 다음 Media Type을 사용한다.
image/png
개발자는 파일의 실제 바이트 데이터를 전달할 수 있다.
이러한 구조에서는 이미지를 Base64 문자열로 변환해 일반 텍스트 Prompt에 직접 붙이는 방식에 의존하지 않아도 된다.
지원하는 Harness Adapter
공식 발표는 다음 Adapter를 지원 대상으로 안내한다.
- Claude Code
- Cline
- Codex
- Cursor
- Deep Agents
- fx
- GitHub Copilot
- Grok Build
- OpenCode
- Pi
이는 기존에 지원하던 Harness Adapter 전체에 이미지 입력 기능을 추가했다는 의미다.
따라서 애플리케이션이 어떤 코딩 에이전트 Harness를 사용하는지에 따라 이미지 입력 구조를 완전히 새롭게 설계해야 하는 부담이 줄어든다.
하지만 모든 Adapter가 동일한 이미지 분석 능력을 제공한다는 의미는 아니다.
실제 이미지 분석은 각 Harness가 사용하는 기반 Vision Model에서 수행된다.
따라서 모델에 따라 다음 항목이 달라질 수 있다.
- 이미지 해상도 제한
- 지원 이미지 형식
- 여러 이미지의 처리 능력
- 이미지 분석 정확도
- 비용 및 토큰 사용량
HarnessAgent가 이미지 입력을 전달할 수 있다는 사실과 실제 모델이 이미지 내용을 정확하게 이해한다는 사실은 구분해야 한다.
Sandbox와의 연결
Vercel 공식 예제에서는 HarnessAgent를 Sandbox와 연결한다.
예를 들어 Codex Harness를 사용하는 Agent를 생성할 수 있다.
이후 Vercel Sandbox Session을 만든다.
Sandbox에는 프로젝트 파일과 코드 실행 환경을 제공한다.
에이전트는 이미지와 텍스트를 입력받아 코드를 생성하거나 수정할 수 있다.
예를 들어 다음 작업을 구성할 수 있다.
- 사용자가 UI 스크린샷을 업로드한다.
- 에이전트가 이미지와 요구사항을 분석한다.
- 프로젝트의 React 컴포넌트를 수정한다.
- Sandbox에서 빌드 또는 테스트를 수행한다.
- 결과를 반환한다.
다만 이번 발표는 이미지 입력을 지원하는 기능에 관한 것이다.
이미지와 실제 구현 화면을 자동으로 픽셀 단위 비교하거나 UI가 완전히 동일한지 검증하는 기능까지 제공한다고 볼 수는 없다.
이러한 검증이 필요하다면 Screenshot Test나 Visual Regression Test 등을 별도로 구성해야 한다.
이번 업데이트는 AI 코딩 에이전트의 입력 범위를 자연어 텍스트에서 실제 화면 이미지까지 확장하면서 여러 Harness에서 공통 메시지 구조를 사용할 수 있도록 한 개발 도구 개선이다.
Vercel Agent, 세션당 평균 비용 67% 감소 — Context 재사용과 Prompt Cache 개선
- 발표일: 2026-10-27 — 정확한 게시 시각 미확인
- 적용 대상: Vercel Agent, Dashboard 및 Slack Session
- 발표 수치: 평균 세션 비용 67% 감소
- 측정 주체: Vercel 자체 측정
- 원문: https://vercel.com/changelog/vercel-agent-sessions-now-cost-67-percent-less
Vercel이 Agent의 Context 관리와 Prompt Cache 사용 방식을 변경해 세션당 평균 비용을 67% 줄였다고 발표했다.
이번 변경은 새로운 모델의 출시나 API 요금 인하와는 다르다.
동일한 작업을 수행할 때 불필요하게 사용하던 토큰을 줄이는 방향의 최적화다.
AI 코딩 에이전트는 하나의 작업을 수행하면서 모델을 여러 번 호출한다.
예를 들어 사용자가 배포 오류를 분석해 달라고 요청하면 에이전트는 로그를 확인하고, 설정 파일을 읽고, 문제를 해결하기 위한 방법을 계획할 수 있다.
이러한 과정에서는 이전 대화 기록과 도구 호출 결과가 다음 모델 요청에도 전달될 수 있다.
문제는 이러한 Context가 계속 증가할 수 있다는 점이다.
특히 Slack에서 긴 대화가 이어지는 경우 이전 메시지를 반복해서 모델에 전달해야 할 수 있다.
Incremental Context 관리
Vercel은 세션이 길어질수록 Context를 더 효율적으로 관리하도록 변경했다.
핵심은 이전에 처리한 정보를 불필요하게 반복해서 생성하거나 전달하는 작업을 줄이는 것이다.
예를 들어 동일한 배포 로그를 여러 번 분석하지 않아도 되는 상황이라면 이전 결과를 재사용할 수 있다.
또한 사용자와 에이전트가 여러 차례 대화하는 동안 공통 Context를 유지하도록 구성할 수 있다.
하지만 Context를 줄이는 과정에는 트레이드오프가 존재한다.
이전 대화의 중요한 정보까지 제거하면 에이전트의 판단에 영향을 줄 수 있기 때문이다.
따라서 실제 최적화에서는 어떤 정보를 유지하고 어떤 정보를 줄일지 결정해야 한다.
Prompt Cache 재사용
Vercel은 Prompt Cache의 재사용도 개선했다.
Prompt Cache는 모델 제공업체가 이전에 처리한 입력 일부를 다시 활용할 수 있도록 하는 기능이다.
예를 들어 여러 요청에서 동일한 시스템 지침과 도구 정의를 반복해서 사용한다고 가정해 보자.
해당 정보를 캐시에서 재사용할 수 있다면 새로운 입력으로 처리하는 비용을 줄일 수 있다.
하지만 입력의 구성이 매번 크게 달라지면 캐시 재사용률이 낮아질 수 있다.
Vercel은 Agent의 공통 Context를 더 안정적으로 유지해 캐시를 재사용하도록 변경했다.
또한 일반적인 작업에 대한 CLI Skill과 실행 계획 지침도 개선했다.
이렇게 하면 에이전트가 불필요한 호출이나 재시도를 줄일 가능성이 있다.
실제 요금 구조
이번 발표에서 중요한 점은 Vercel Agent의 요금 단가 자체는 변경되지 않았다는 사실이다.
유료 세션은 다음 비용 구조를 사용한다.
- 모델 제공업체의 추론 비용
- Vercel Agent의 추가 요금
Vercel Agent의 추가 요금은 다음과 같다.
토큰 100만 개당 0.25달러
따라서 세션당 평균 비용이 67% 감소했다는 발표는 기본 요금 단가를 67% 인하했다는 의미가 아니다.
Context 관리와 Cache 사용을 개선해 실제 소비하는 토큰의 양과 비용을 줄였다는 의미다.
Vercel은 해당 개선이 이미 적용됐으며 별도의 설정 변경이 필요하지 않다고 설명한다.
발표 수치의 한계
67%라는 수치는 Vercel이 자체적으로 측정한 평균 결과다.
모든 사용자와 모든 세션에서 동일한 비용 절감 효과가 발생한다는 의미는 아니다.
예를 들어 한 번의 짧은 요청으로 종료되는 세션은 반복적인 Context 전달이 적다.
따라서 Cache 개선으로 절약할 수 있는 비용도 상대적으로 작을 수 있다.
반면 긴 대화와 여러 도구 호출이 반복되는 세션에서는 효과가 더 클 수 있다.
또한 실제 비용은 모델의 토큰 요금과 Cache 정책에 영향을 받는다.
이번 발표에는 품질을 동일한 조건으로 평가한 독립적인 Benchmark가 포함되지 않았다.
따라서 비용이 감소했다고 해서 모든 작업의 결과 품질과 실행 시간이 동일하게 유지된다고 단정할 수는 없다.
이번 업데이트는 AI 에이전트의 실행 비용을 모델 단가만이 아니라 Context 구성과 캐시 재사용, 도구 호출 방식으로 최적화한 사례다.
Google Cloud CLI 591.0.0, macOS 업데이트 오류 수정 — 기존 590.0.x 사용자는 별도 복구 명령 필요
- 발표일: 2026-10-27 — 정확한 게시 시각 미확인
- 버전: Google Cloud CLI 591.0.0
- 변경 유형: 업데이트 오류 수정 및 일부 명령 정식 지원
- 원문: https://docs.cloud.google.com/release-notes/
Google Cloud가 CLI 591.0.0을 공개하면서 macOS에서 업데이트 명령이 중단되던 문제를 수정했다.
이번 릴리스에서 가장 중요한 변경은 새로운 기능보다 기존 CLI 사용자의 업데이트 경로다.
일부 사용자는 다음 명령을 실행했을 때 문제가 발생했다.
gcloud components update
명령을 실행하면 Python Module 업데이트와 관련된 경고가 표시된 뒤 실제 업데이트가 진행되지 않을 수 있었다.
문제는 다음 두 버전에 존재했다.
- 590.0.0
- 590.0.1
새로운 591.0.0에서는 해당 문제가 수정됐다.
하지만 이미 영향을 받는 버전을 사용하고 있다면 정상적인 업데이트 명령 자체가 실행되지 않을 수 있다.
따라서 수정 버전이 존재하더라도 해당 버전까지 업데이트하기 어려운 문제가 남는다.
Google Cloud는 이를 위해 한 번만 실행하면 되는 우회 명령을 안내했다.
gcloud components --flags-file=<(echo 'update:')
이 명령은 영향을 받는 CLI 환경에서 업데이트를 진행할 수 있도록 하는 용도다.
공식 문서에 따르면 다음 환경에서는 별도의 우회가 필요하지 않다.
- 589.0.0 이하
- 591.0.0 이상
따라서 모든 사용자가 해당 우회 명령을 실행해야 하는 것은 아니다.
Bundled Python 업데이트
이번 릴리스에서는 CLI에 포함되는 Python도 업데이트됐다.
새로운 버전은 다음과 같다.
Python 3.14.9
다만 Google Cloud CLI에 Bundled Python이 포함됐다는 사실이 사용자의 운영체제에 설치된 기본 Python 버전을 변경한다는 의미는 아니다.
CLI가 자체적으로 사용하는 Python 런타임에 관한 변경이다.
Agent Registry 명령 정식 지원
이번 업데이트에서는 Agent Registry의 일부 명령도 Generally Available 상태로 변경됐다.
대표적으로 다음 명령 그룹이 포함된다.
gcloud agent-registry skillsgcloud agent-registry skills revisionsgcloud agent-registry publishersgcloud agent-registry findings
이는 기존 Preview 명령을 정식 지원 범위로 확대한 변경이다.
다만 관련 API와 서비스의 접근 권한, 실제 이용 가능 여부는 프로젝트 설정과 사용 중인 Google Cloud 서비스에 따라 달라질 수 있다.
이번 릴리스는 개발 도구의 업데이트 경로를 복구하고 일부 Agent Registry 관리 명령의 안정화 상태를 변경한 CLI 업데이트다.
📚 추천 글
React Markdown alternatives: Benchmarking 3 streaming renderers
- 저자: Chizaram Ken
- 매체: LogRocket
- 게시일: 2026-10-27
- 원문: https://blog.logrocket.com/react-markdown-alternatives-benchmarking-3-streaming-renderers/
React 애플리케이션에서 AI 모델이 생성하는 Markdown을 실시간으로 표시할 때 어떤 렌더러가 실제로 브라우저의 메인 스레드를 얼마나 사용하는지 비교한 성능 실험이다.
이번 글은 단순히 유명한 Markdown 라이브러리를 기능별로 소개하지 않는다.
저자는 실제 AI 모델의 응답을 저장한 뒤 같은 입력을 여러 렌더러에 전달했다.
그리고 브라우저에서 실제로 발생한 Main-thread Task와 Frame 지연, DOM 변경까지 측정했다.
특히 긴 코드 블록에 Syntax Highlighting을 적용하는 경우 일반적인 react-markdown 구현에서 처리 비용이 크게 증가할 수 있다는 점을 구체적인 수치로 보여준다.
비교 대상
이번 실험에서는 다음 라이브러리를 사용했다.
- react-markdown
- Streamdown
- Markstream
- Comark
react-markdown은 일반적인 Markdown을 React Element로 변환하는 라이브러리다.
반면 Streamdown과 Markstream, Comark는 스트리밍되는 텍스트를 처리하는 기능에 초점을 맞춘다.
저자는 react-markdown도 두 가지 설정으로 나누어 테스트했다.
첫 번째는 기본적인 Markdown 렌더링이다.
두 번째는 rehype-highlight를 추가해 코드의 Syntax Highlighting을 수행하는 방식이다.
따라서 실제 비교 대상은 다음 다섯 가지 설정이다.
| 설정 | 주요 특징 |
|---|---|
| react-markdown | 기본 Markdown 렌더링 |
| react-markdown + rehype-highlight | 코드 Highlighting 추가 |
| Streamdown | 스트리밍 Markdown 지원 |
| Markstream | 스트리밍 노드 렌더링 |
| Comark | 스트리밍 Markdown 및 Plugin 사용 |
중요한 점은 라이브러리 이름만 비교한 것이 아니라 각 라이브러리의 실제 구성까지 함께 비교했다는 사실이다.
예를 들어 Syntax Highlighting을 사용하는 설정과 사용하지 않는 설정은 처리 비용이 다를 수 있다.
따라서 이번 결과를 라이브러리의 절대적인 성능 순위로 해석해서는 안 된다.
스트리밍 Markdown이 어려운 이유
일반적인 Markdown은 전체 문자열이 완성된 이후 파싱할 수 있다.
예를 들어 다음과 같은 문서다.
제목과 문단, 코드 블록이 모두 완성된 상태다.
하지만 AI 모델이 Markdown을 스트리밍하는 상황은 다르다.
처음에는 문자열 일부만 도착한다.
이후 문단의 나머지가 도착한다.
또 다음 Chunk에서 코드 블록을 시작하는 기호가 도착할 수 있다.
예를 들어 다음 문자열을 생각할 수 있다.
```javascript
const total =
이 문자열은 아직 완성된 코드 블록이 아니다.
나중에 추가되는 Chunk에 따라 최종 구조가 달라질 수 있다.
또한 Markdown Table도 비슷하다.
처음에는 일반적인 문자열처럼 보이던 텍스트가 나중에 구분선이 도착하면서 표 구조로 해석될 수 있다.
따라서 스트리밍 Markdown 렌더러는 불완전한 문서를 반복해서 처리해야 한다는 문제를 가진다.
react-markdown의 반복 파싱
일반적인 React 구현에서는 모델이 새로운 Chunk를 반환할 때마다 현재까지 생성한 전체 문자열을 State에 저장할 수 있다.
예를 들어 첫 번째 Chunk가 도착하면 100글자를 렌더링한다.
두 번째 Chunk가 도착하면 누적된 200글자를 렌더링한다.
세 번째 Chunk가 도착하면 누적된 300글자를 렌더링한다.
이러한 방식에서는 뒤에 새로운 문자열만 추가됐더라도 react-markdown이 전체 Markdown 문자열을 다시 파싱할 수 있다.
문서가 길어질수록 한 번의 파싱에서 처리해야 하는 문자열의 크기도 증가한다.
특히 코드 블록의 Syntax Highlighting을 수행한다면 Parser 외에 Highlighting Plugin의 작업도 반복될 수 있다.
이러한 작업이 브라우저의 메인 스레드에서 실행되면 다른 UI 작업을 처리할 수 있는 시간이 줄어들 수 있다.
실제 테스트 데이터
저자는 실제 모델 응답을 저장해 테스트에 사용했다.
테스트 데이터는 다음과 같다.
| 데이터 | 길이 | 주요 내용 |
|---|---|---|
| Short | 1,963자 | 일반 텍스트 |
| Medium | 4,703자 | 코드 블록 및 표 |
| Long | 22,229자 | 코드 블록 6개, 표 2개 |
| Diagram | 4,599자 | Mermaid Diagram |
특히 Long 데이터에는 실제로 기록된 Chunk가 1,993개 존재했다.
따라서 단순히 완성된 22,229자의 Markdown을 한 번 렌더링하는 테스트가 아니다.
실제 AI 응답처럼 여러 Chunk가 순차적으로 도착하는 상황을 재현한 것이다.
테스트 환경
저자는 다음 환경을 사용했다.
- React 19
- Vite
- Playwright
- Headless Chromium
- Apple M4 MacBook Air
테스트에서는 Production Build를 사용했다.
또한 두 종류의 스트리밍 속도를 실험했다.
첫 번째는 실제 기록된 Chunk 도착 시간의 간격을 10배 빠르게 재생하는 방식이다.
두 번째는 requestAnimationFrame에 맞춰 24글자씩 전달하는 방식이다.
CPU 역시 두 조건으로 나누어 테스트했다.
- 일반적인 CPU 속도
- 4배 CPU Throttling
CPU Throttling은 브라우저의 JavaScript 실행을 더 느리게 처리하도록 만들어 성능 문제를 관찰하는 방법이다.
다만 M4 MacBook Air에서 4배 Throttling을 적용했다고 해서 특정 저가형 스마트폰과 동일한 성능 환경이 만들어지는 것은 아니다.
저자는 이 한계를 명시한다.
측정한 지표
이번 실험에서는 여러 지표를 측정했다.
| 지표 | 의미 |
|---|---|
| Time to First Text | 첫 텍스트가 표시되기까지 걸린 시간 |
| Main-thread Task Time | 메인 스레드가 작업을 처리하는 데 사용한 누적 시간 |
| Chunk-to-mutation Latency | Chunk가 도착한 뒤 DOM 변경이 관찰되기까지의 시간 |
| Long Frame Gap | Frame 사이 간격이 33.4ms를 초과한 횟수 |
| Long Task | 메인 스레드 작업이 50ms 이상 지속된 횟수 |
이 지표들은 서로 다른 문제를 측정한다.
예를 들어 Main-thread Task Time이 짧다고 해서 화면의 모든 Frame이 부드럽게 표시된다는 의미는 아니다.
특정 작업이 한 번에 오래 실행돼 화면이 순간적으로 멈출 수도 있기 때문이다.
반대로 Long Task가 0개라고 해서 모든 Animation Frame이 정상적인 간격으로 표시된다는 의미도 아니다.
50ms보다 짧은 작업이 반복되더라도 Frame 지연이 발생할 수 있다.
따라서 저자는 여러 지표를 함께 사용했다.
짧은 응답에서는 react-markdown도 충분히 빨랐다
Short와 Medium 데이터에서는 예상보다 작은 차이가 나타났다.
일반적인 react-markdown 구성은 긴 Frame Gap이 거의 발생하지 않았다.
저자가 측정한 조건에서는 Short와 Medium 데이터에서 33.4ms를 초과하는 Frame Gap의 중앙값이 0이었다.
즉 짧은 AI 응답을 렌더링하는 애플리케이션에서는 반드시 전용 스트리밍 Markdown 렌더러가 필요한 것은 아닐 수 있다.
이 결과는 중요한 트레이드오프를 보여준다.
라이브러리를 교체하면 새로운 API와 렌더링 동작, CSS 및 Plugin 구성을 관리해야 한다.
따라서 현재 문제가 발생하지 않는 작은 프로젝트에서 단순히 스트리밍 전용이라는 이유만으로 새로운 라이브러리를 도입하는 것이 최선은 아닐 수 있다.
긴 응답과 Syntax Highlighting에서 차이가 커졌다
Long 데이터에서는 결과가 달라졌다.
특히 CPU Throttling을 적용하고 Syntax Highlighting을 사용하는 경우 처리 지연이 증가했다.
저자가 공개한 결과에 따르면 react-markdown + rehype-highlight의 Chunk-to-mutation Latency는 문서가 길어질수록 증가했다.
초기 구간에서는 약 3.7ms였다.
반면 마지막 구간에서는 약 42.3ms까지 증가했다.
특히 약 7,000자 이후부터는 일부 구간에서 16.7ms를 초과했다.
60Hz 디스플레이에서 한 Frame의 시간은 약 16.7ms다.
따라서 하나의 작업이 이 시간을 많이 사용하면 브라우저가 사용자 입력과 화면 갱신을 처리할 여유가 줄어들 수 있다.
하지만 7,000자라는 수치가 모든 프로젝트의 성능 저하 기준은 아니다.
해당 문서의 코드 블록과 Plugin 구성, CPU Throttling 설정에 따른 결과다.
긴 응답의 렌더러별 성능 비교
저자가 공개한 Long 데이터의 Frame-paced 및 4배 CPU Throttling 조건 결과는 다음과 같다.
| 렌더링 설정 | 메인 스레드 작업 시간 | Long Frame Gap | 가장 긴 Frame 간격 |
|---|---|---|---|
| react-markdown | 11.6초 | 0회 | 33.1ms |
| react-markdown + rehype-highlight | 23.1초 | 269회 | 54.1ms |
| Markstream | 3.7초 | 1회 | 41.1ms |
| Streamdown | 6.2초 | 12회 | 1,053.5ms |
| Comark | 154.5초 | 850회 | 344.5ms |
이 결과에서 가장 적은 메인 스레드 작업 시간을 사용한 것은 Markstream이었다.
하지만 Streamdown 역시 Highlighting을 사용하는 react-markdown보다 전체 작업 시간이 짧았다.
반면 Streamdown에서는 가장 긴 Frame 간격이 1초를 초과했다.
이는 전체 작업 시간이 짧더라도 특정 시점에 긴 지연이 발생할 수 있다는 의미다.
따라서 전체 처리량과 실제 사용자에게 느껴지는 부드러움은 구분해야 한다.
Comark의 결과를 그대로 해석하면 안 되는 이유
이번 실험에서 가장 느린 결과를 기록한 것은 Comark였다.
하지만 저자는 이 결과를 Comark 자체의 일반적인 성능으로 판단해서는 안 된다고 설명한다.
테스트에 사용한 Comark Adapter에서는 다음 Plugin을 컴포넌트 렌더링 과정에서 생성했다.
- shiki()
- mermaidPlugin()
따라서 React 컴포넌트가 다시 렌더링될 때마다 새로운 Plugin 인스턴스가 생성될 수 있었다.
이 경우 Markdown을 파싱하는 비용뿐 아니라 Plugin을 생성하는 비용도 측정 결과에 포함된다.
저자는 Plugin 인스턴스를 안정적으로 유지하는 방식으로 다시 측정할 필요가 있다고 설명한다.
즉 이번 결과만으로 Comark가 다른 라이브러리보다 항상 수십 배 느리다고 결론 내릴 수 없다.
테스트 결과의 한계
이번 Benchmark는 재현 가능한 공개 테스트 프로젝트를 사용했다.
하지만 실제 성능은 다음 요소에 영향을 받을 수 있다.
- Markdown 문서의 길이
- 코드 블록의 개수
- Highlighting Library
- Mermaid Diagram 사용 여부
- 모델의 Chunk 생성 속도
- 브라우저의 JavaScript 실행 성능
- React 컴포넌트의 구조
또한 일부 렌더러는 서로 다른 Syntax Highlighting 구현을 사용했다.
따라서 모든 렌더러가 정확히 동일한 작업을 수행하도록 통제한 실험은 아니다.
이번 글은 AI 채팅 UI에서 Markdown이 길어질수록 반복 파싱과 Syntax Highlighting 비용이 누적될 수 있다는 점을 실제 브라우저 측정으로 검증한 자료다.
특히 메인 스레드 작업 시간과 Frame Gap을 별도로 측정했다는 점이 중요하다.
How much faster is the new Angular compiler?
- 저자: Cédric Exbrayat
- 매체: Ninja Squad
- 게시일: 2026-10-27
- 원문: https://blog.ninja-squad.com/2026/10/27/how-much-faster-is-the-new-angular-compiler
Angular가 개발하고 있는 Rust 기반 차세대 컴파일러 ngp의 내부 구조를 분석하고 기존 컴파일러와 실행 시간 및 메모리 사용량을 비교한 기술 글이다.
이번 글의 핵심은 단순히 Rust가 JavaScript보다 빠르다는 주장이 아니다.
Angular 컴파일러가 어떤 작업을 수행하는지 분리하고, 그중 어떤 부분을 Rust로 이전했으며 어떤 부분은 여전히 기존 TypeScript 구현을 사용하는지 설명한다.
또한 실제로 세 가지 규모의 Angular 프로젝트를 컴파일하면서 성능 차이를 측정했다.
기존 Angular 컴파일러 ngc
Angular에서는 컴포넌트의 Template을 실제 JavaScript 실행 코드로 변환해야 한다.
예를 들어 다음과 같은 Template이 있다고 가정해 보자.
Hello {{ name() }}
이 Template은 단순한 HTML 문자열이 아니다.
name()이라는 표현식의 결과를 화면에 표시해야 한다.
또한 값이 변경되면 화면의 텍스트도 변경해야 한다.
따라서 Angular 컴파일러는 Template을 분석한 뒤 실제 DOM을 생성하고 업데이트하는 코드를 만든다.
이 과정에서 TypeScript의 타입 검사도 중요하다.
예를 들어 Template에서 존재하지 않는 속성이나 잘못된 함수를 호출했다면 컴파일 단계에서 오류를 발견할 수 있어야 한다.
기존 Angular 컴파일러인 ngc는 TypeScript 컴파일러와 깊게 연결돼 있다.
특히 TypeScript의 Transformer API를 이용해 코드의 내부 표현을 변경하는 방식이 사용돼 왔다.
하지만 이러한 구조에는 문제가 발생했다.
TypeScript 7에서는 기존 컴파일러가 Go로 다시 구현됐다.
그런데 새로운 TypeScript 컴파일러는 기존 JavaScript 기반 Transformer API와 동일한 구조를 제공하지 않는다.
따라서 Angular가 기존 구조를 유지하면서 새로운 TypeScript 컴파일러의 성능을 그대로 활용하기 어려웠다.
ngp의 핵심 설계
Angular의 새로운 컴파일러는 ngp라고 부른다.
핵심 설계는 Angular 코드 생성과 TypeScript 타입 검사를 분리하는 것이다.
기존 컴파일러는 TypeScript의 컴파일 과정에 깊게 연결돼 있었다.
반면 ngp는 Angular 코드에서 필요한 정보를 분석하고 TypeScript 코드를 생성한다.
이후 실제 타입 검사는 별도의 TypeScript 컴파일러가 수행할 수 있다.
JavaScript 코드 생성도 별도의 도구가 담당할 수 있다.
저자는 이러한 구조를 세 단계로 구분한다.
| 단계 | 수행 작업 | 사용 기술 |
|---|---|---|
| 1단계 | Angular 코드 분석과 Metadata 수집 | Rust, Oxc |
| 2단계 | Template의 Runtime Code 및 Type Check Block 생성 | 기존 Angular TypeScript 컴파일러 |
| 3단계 | 타입 검사 및 JavaScript 생성 | TypeScript 7, esbuild, Rolldown 등 |
이러한 구조의 장점은 각 단계에 적합한 도구를 사용할 수 있다는 것이다.
예를 들어 JavaScript의 타입 검사와 실제 JavaScript 코드 생성은 서로 다른 작업이다.
타입 검사에는 TypeScript의 타입 시스템이 필요하다.
반면 실제 JavaScript 코드를 생성할 때는 TypeScript 문법을 제거하고 필요한 코드를 출력하는 도구를 사용할 수 있다.
Rust 분석 단계
첫 번째 단계에서는 Rust 기반의 Oxc를 사용한다.
Oxc는 JavaScript와 TypeScript 코드를 빠르게 분석하고 변경하기 위한 도구 체인이다.
이 단계에서는 Angular 컴포넌트의 다음 정보를 수집한다.
- 클래스 이름
- Decorator
- Selector
- Template
- Metadata
- 컴포넌트 간 관계
예를 들어 @Component Decorator가 존재하면 해당 클래스를 Angular 컴포넌트로 인식한다.
이후 필요한 정보를 TypeScript 기반 Template Compiler에 전달한다.
중요한 점은 Rust 분석 단계가 Template 전체를 최종 JavaScript 코드로 변환하는 것은 아니라는 사실이다.
이번 구현에서는 기존 Angular Template Compiler를 여전히 사용한다.
따라서 Angular 컴파일러의 모든 코드가 Rust로 다시 작성된 것은 아니다.
Runtime Code와 Type Check Block 분리
두 번째 단계에서는 기존 Angular Template Compiler를 사용해 두 종류의 TypeScript 파일을 생성한다.
첫 번째는 실제 실행에 사용할 Runtime Code다.
예를 들어 Template에 포함된 HTML 요소를 생성하고 텍스트를 업데이트하는 코드가 포함된다.
두 번째는 Type Check Block(TCB)이다.
TCB는 Template 안의 표현식이 올바른 타입을 사용하는지 검사하기 위한 코드다.
예를 들어 다음 표현식을 생각할 수 있다.
name()
TypeScript는 해당 함수가 실제로 존재하는지 확인할 수 있다.
또한 함수가 반환하는 값이 해당 위치에서 사용할 수 있는 타입인지 검사할 수 있다.
하지만 이러한 검사를 위해 생성한 TCB가 실제 브라우저에 모두 전달될 필요는 없다.
TCB는 컴파일 과정에서 타입 검사를 수행하는 데 사용된다.
반면 Runtime Code는 실제 JavaScript로 변환돼 애플리케이션에 포함될 수 있다.
이렇게 하면 타입 검사를 위한 코드와 실제 실행 코드를 서로 독립적으로 처리할 수 있다.
TypeScript 7과 esbuild의 역할
세 번째 단계에서는 TypeScript 7을 이용해 타입을 검사할 수 있다.
저자는 tsgo를 사용했다.
그리고 JavaScript 생성에는 esbuild를 사용했다.
esbuild는 JavaScript와 TypeScript를 빠르게 처리하는 빌드 도구다.
TypeScript의 타입을 검사하는 대신 문법을 제거하고 JavaScript를 출력하는 작업을 빠르게 수행할 수 있다.
따라서 두 작업을 분리할 수 있다.
- TypeScript: 타입 검사
- esbuild: JavaScript 생성
저자는 Rust 기반의 다른 도구 조합도 실험했다.
대표적으로 다음 도구를 사용했다.
- tsrs
- Rolldown
tsrs는 TypeScript 컴파일러를 Rust로 구현하려는 프로젝트다.
Rolldown은 Rust 기반 JavaScript Bundler다.
이러한 구조에서는 TypeScript 타입 검사와 JavaScript 생성에 서로 다른 구현을 사용할 수 있다.
다만 실제 Angular CLI가 앞으로 어떤 조합을 정식으로 채택할지는 확정되지 않았다.
실제 Benchmark
저자는 새로운 ngp 컴파일러를 직접 빌드한 뒤 세 프로젝트에서 실행했다.
실험에 사용한 프로젝트 규모는 다음과 같다.
| 프로젝트 | 컴포넌트 수 |
|---|---|
| Small | 15개 |
| Medium | 56개 |
| Large | 1,714개 |
사용한 Angular Compiler는 22.3.0-next.2 기반의 개발 버전이다.
또한 TypeScript 7.1 Beta를 사용했다.
JavaScript 생성에는 esbuild와 Rolldown을 사용했다.
중요한 점은 이번 실험이 Cold Build를 기준으로 수행됐다는 사실이다.
Cold Build는 기존의 빌드 캐시를 재사용하지 않는 상태에서 전체 빌드를 실행하는 방식이다.
따라서 개발자가 파일 하나를 수정한 뒤 실행하는 Incremental Build와는 다를 수 있다.
측정 결과
저자는 새로운 ngp 구조가 기존 ngc보다 약 2~3배 빠른 컴파일 결과를 보였다고 발표했다.
또한 대규모 프로젝트에서는 메모리 사용량도 감소했다.
| 항목 | 기존 ngc | 새로운 ngp 기반 구성 |
|---|---|---|
| 컴파일 성능 | 기준 | 약 2~3배 빠름 |
| 대규모 프로젝트 메모리 | 약 2.8GB | 약 1.4GB |
메모리 사용량은 약 절반으로 감소했다.
하지만 이 수치는 특정 프로젝트와 실행 환경에서 측정한 값이다.
모든 Angular 애플리케이션에서 메모리 사용량이 반드시 절반으로 줄어든다는 의미는 아니다.
또한 이번 Benchmark는 Ninja Squad가 직접 수행한 초기 실험이다.
Angular 공식 팀이 안정화된 최종 버전을 이용해 발표한 성능 보장 수치가 아니다.
아직 실제 Angular CLI의 기본 컴파일러는 아니다
이번 글에서 가장 중요한 제한사항은 안정화 단계다.
ngp는 아직 개발 중인 내부 컴파일러다.
저자가 사용한 버전도 Beta 또는 Next 계열의 개발 버전이다.
또한 기존 Angular 컴파일러와 동일한 테스트를 수행했을 때 일부 테스트는 아직 통과하지 못하고 있다고 설명한다.
따라서 일반적인 Angular 프로젝트에서 CLI를 업데이트하면 곧바로 새로운 Rust 기반 컴파일러가 기본으로 실행된다고 가정해서는 안 된다.
현재는 컴파일러의 구조와 성능을 실험하는 단계다.
실제 Angular CLI와의 통합과 모든 언어 기능의 호환성 검증은 계속 진행 중이다.
성능 개선이 실제 사용자 성능과 같은 것은 아니다
이번 결과는 Angular 애플리케이션을 컴파일하는 데 필요한 시간을 측정한 것이다.
따라서 브라우저에서 실행되는 Angular 애플리케이션의 렌더링 속도가 2~3배 빨라졌다는 의미는 아니다.
실제 생성된 Runtime Code는 기존 Angular의 Template Compiler를 사용한다.
따라서 주요 개선 대상은 빌드 과정이다.
특히 다음 영역에서 효과가 기대된다.
- 대규모 프로젝트의 Cold Build
- TypeScript 타입 검사
- 컴파일러의 메모리 사용량
- 개발 환경의 코드 변경 처리
다만 Incremental Build의 실제 성능은 별도의 측정이 필요하다.
저자는 같은 구조의 개선이 Incremental Build에도 도움이 될 것으로 예상하지만, 이번에 제시한 수치는 Cold Build에 관한 것이다.
이번 글은 TypeScript와 Angular의 컴파일 과정을 분리하고 Rust 기반 분석 도구를 도입해 실제 개발 도구의 성능을 개선하는 방법을 내부 구조와 Benchmark로 설명한다.
특히 코드 분석과 타입 검사, JavaScript 생성이라는 세 가지 작업을 분리해 이해할 수 있는 자료다.
Teaching AI agents your design system: Building a component contract with Google’s OKF
- 저자: Ikeh Akinyemi
- 매체: LogRocket
- 게시일: 2026-10-22
- 원문: https://blog.logrocket.com/teaching-ai-agents-design-system-building-component-contract-google-okf/
AI 코딩 에이전트에게 React 디자인 시스템의 정보를 전달할 때 전체 컴포넌트 문서를 하나의 거대한 Prompt에 포함하는 방식과 필요한 문서만 선택적으로 읽는 방식을 실제로 비교한 글이다.
이번 글의 특징은 단순히 AI에게 디자인 시스템 문서를 제공하면 결과가 좋아진다는 주장에 그치지 않는다는 점이다.
저자는 실제 React 컴포넌트 라이브러리인 Primer React를 이용해 문서를 생성했다.
이후 AI 에이전트가 실제 컴포넌트 API를 올바르게 사용하는지 테스트했다.
또한 문서의 크기와 토큰 사용량, 생성한 코드의 정확도까지 측정했다.
AI 에이전트가 오래된 컴포넌트 API를 사용하는 문제
AI 코딩 에이전트는 공개된 React 코드와 문서를 학습했을 수 있다.
하지만 실제 프로젝트에서 사용하는 컴포넌트 라이브러리의 버전은 다를 수 있다.
예를 들어 기존 Primer React에는 특정 컴포넌트가 존재했지만 새로운 버전에서는 제거됐을 수 있다.
또한 컴포넌트의 Props 이름이 변경됐을 수도 있다.
이때 AI 에이전트는 이전 버전의 API를 사용해 코드를 작성할 수 있다.
예를 들어 다음과 같은 문제가 발생한다.
- 더 이상 Export되지 않는 컴포넌트 Import
- Deprecated 상태의 컴포넌트 사용
- 제거된 Props 전달
- 다른 Entry Point에서 Import해야 하는 컴포넌트 사용
이러한 문제는 TypeScript가 일부 발견할 수 있다.
예를 들어 존재하지 않는 Export를 Import하려고 하면 컴파일 오류가 발생할 수 있다.
하지만 Deprecated 상태의 컴포넌트는 여전히 TypeScript 컴파일에 성공할 수 있다.
따라서 단순히 타입 검사를 통과했다고 해서 실제 프로젝트의 디자인 시스템 정책을 준수한 것은 아니다.
Google OKF의 구조
저자는 Google의 Open Knowledge Format(OKF)을 사용했다.
OKF는 정보를 여러 문서로 나누어 저장하고 AI 에이전트가 필요한 내용을 찾아 읽도록 하기 위한 형식이다.
문서는 Markdown을 사용한다.
그리고 각 문서의 앞부분에는 YAML Frontmatter가 포함된다.
예를 들어 특정 컴포넌트에 다음 정보를 제공할 수 있다.
- 컴포넌트 이름
- Import 경로
- 현재 지원 상태
- Props
- Deprecated 여부
- 대체 컴포넌트
- 문서의 생성 출처
또한 디렉터리마다 index.md를 제공할 수 있다.
에이전트는 처음부터 모든 컴포넌트 문서를 읽지 않는다.
먼저 Index를 읽는다.
이후 실제 작업에 필요한 컴포넌트의 문서를 선택해서 읽는다.
예를 들어 Dialog를 구현해야 한다면 Dialog 관련 문서를 우선 읽는다.
Button이나 Tooltip이 추가로 필요하다면 해당 문서를 찾아볼 수 있다.
이러한 방식은 전체 디자인 시스템의 정보를 매번 모델 Context에 넣는 대신 필요한 정보만 선택적으로 가져오는 구조다.
Primer React 38.40.1을 기준으로 문서 생성
저자는 GitHub의 컴포넌트 라이브러리인 Primer React를 사용했다.
테스트에 사용한 버전은 다음과 같다.
@primer/react@38.40.1
해당 버전에는 80개의 컴포넌트가 존재했다.
그중 11개는 Deprecated 상태였다.
저자는 각 컴포넌트의 정보에서 하나의 문서를 생성했다.
따라서 총 80개의 Component Concept이 생성됐다.
하지만 이 과정은 단순히 패키지의 Metadata를 그대로 Markdown으로 변환하는 작업이 아니었다.
실제 패키지의 Metadata와 Export 정보가 일치하지 않는 문제가 있었기 때문이다.
Metadata와 실제 Export가 달랐던 사례
예를 들어 Primer의 Metadata에는 특정 컴포넌트가 일반적인 @primer/react 경로에서 Export되는 것으로 기록돼 있었다.
하지만 실제 TypeScript 선언을 확인하면 다른 Entry Point에서만 사용할 수 있는 경우가 존재했다.
대표적인 예가 KeybindingHint다.
실제로는 다음 경로에서 제공된다.
@primer/react/experimental
반면 Metadata에서는 다른 Import 경로가 표시될 수 있었다.
또한 같은 이름의 컴포넌트가 서로 다른 Entry Point에서 제공되는 경우도 존재했다.
대표적으로 다음 컴포넌트가 해당한다.
- Dialog
- Tooltip
- UnderlineNav
- SelectPanel
이러한 문제를 해결하기 위해 저자는 TypeScript Compiler API를 사용했다.
실제 패키지의 .d.ts 파일을 분석한다.
그리고 각 Export가 어떤 소스 디렉터리에서 생성됐는지 확인한다.
이 정보를 Metadata와 연결해 실제 Import 경로를 결정한다.
이는 문서에 기록된 컴포넌트 정보보다 실제 배포된 패키지의 타입 선언을 우선하는 접근이다.
Deprecated 정보를 별도로 처리
저자는 Component Concept에 Deprecated 정보를 포함했다.
예를 들어 Flash 컴포넌트는 Deprecated 상태다.
대체 컴포넌트로 Banner를 사용할 수 있다.
따라서 해당 문서에는 다음 정보가 포함된다.
- status: deprecated
- replaced_by
이렇게 하면 AI 에이전트가 오래된 컴포넌트의 문서를 발견하더라도 현재 권장하는 대체 컴포넌트를 확인할 수 있다.
하지만 모든 Deprecated 컴포넌트에 명확한 대체 API가 존재하는 것은 아니다.
이러한 경우에는 팀이 직접 작성한 가이드가 필요할 수 있다.
저자는 자동으로 생성할 수 있는 정보와 사람이 결정해야 하는 정보를 분리했다.
자동 생성한 문서에는 실제 패키지 버전과 생성 정보를 기록한다.
사람이 직접 작성한 가이드에는 작성자와 검토 시점, 재검토 기한을 포함할 수 있다.
다만 문서에 검토 기한이 존재한다는 사실만으로 실제 재검토가 자동으로 수행되는 것은 아니다.
이를 강제하려면 별도의 CI 검사가 필요하다.
Flat File과 선택적 문서 로딩 비교
저자는 두 가지 문서 제공 방식을 비교했다.
첫 번째는 전체 디자인 시스템 문서를 하나의 CLAUDE.md 파일에 넣는 방식이다.
두 번째는 짧은 안내문만 제공하고 실제 문서는 OKF Bundle에서 필요할 때 읽도록 하는 방식이다.
Flat File의 크기는 약 149KB였다.
저자는 간단한 모델 요청을 이용해 기본 Context 사용량을 측정했다.
결과는 다음과 같았다.
| 조건 | 전체 입력 토큰 | 디자인 시스템 문서로 추가된 토큰 |
|---|---|---|
| 빈 Workspace | 5,810 | 0 |
| OKF 안내문 | 6,027 | 217 |
| 전체 Flat File | 64,299 | 58,489 |
OKF 안내문은 초기 Context에 217토큰을 추가했다.
반면 전체 Flat File은 58,489토큰을 추가했다.
차이가 매우 크다.
하지만 이 수치에서 주의해야 할 점이 있다.
OKF 방식에서 실제 작업을 수행하려면 관련 문서를 추가로 읽어야 한다.
따라서 전체 작업에 사용되는 토큰이 항상 217개만 증가하는 것은 아니다.
이번 수치는 세션 시작 시점의 Context 사용량을 비교한 것이다.
실제 작업에서는 문서 검색과 파일 읽기, 모델 응답과 수정 작업에 추가 비용이 발생한다.
TypeScript와 별도의 Contract Checker
저자는 디자인 시스템의 규칙을 문서로만 제공하지 않았다.
AI 에이전트가 작성한 코드가 해당 규칙을 충족하는지 검사하는 도구도 구현했다.
검사에는 두 가지 방법을 사용했다.
첫 번째는 TypeScript Compiler의 Diagnostics다.
예를 들어 존재하지 않는 Export를 Import하려는 코드를 발견할 수 있다.
두 번째는 자체적으로 작성한 Deprecated 검사다.
예를 들어 타입 검사는 통과하지만 Deprecated 상태인 Flash를 사용하는 경우를 발견한다.
또는 IconButton의 Deprecated Prop을 사용하는 상황을 검사할 수 있다.
이렇게 하면 AI 에이전트가 잘못된 API를 사용하더라도 실제 CI에서 해당 문제를 발견할 수 있다.
다만 자체 검사기에도 제한사항이 있다.
다음 패턴을 완전히 처리하지 못할 수 있다.
- Namespace Import
- Wrapper Component
- Spread를 통한 Props 전달
또한 실제 화면의 접근성이나 시각적 품질까지 검증하는 기능은 아니다.
따라서 이번 Contract Checker는 디자인 시스템의 모든 규칙을 검사하는 범용 도구가 아니라 특정 API 사용 패턴을 확인하는 도구다.
CI에서 문서의 최신성 검사
저자는 생성한 문서가 실제 패키지의 버전과 일치하는지도 확인하도록 했다.
예를 들어 @primer/react를 업데이트했다고 가정해 보자.
새로운 버전에서는 컴포넌트가 추가되거나 Props가 변경됐을 수 있다.
하지만 OKF 문서를 다시 생성하지 않으면 오래된 정보가 남는다.
저자는 이를 해결하기 위해 CI에서 문서를 다시 생성한다.
이후 Git의 변경 상태를 검사한다.
문서가 변경됐다면 해당 변경을 실제 Repository에 반영해야 한다.
여기서 중요한 부분은 단순히 git diff만 사용하지 않았다는 것이다.
새롭게 생성된 파일은 아직 Git이 추적하지 않을 수 있다.
따라서 다음 명령을 활용한다.
git status --porcelain --untracked-files=all
이렇게 하면 기존 파일의 변경뿐 아니라 새로 생성된 파일도 확인할 수 있다.
실제 AI 코딩 Benchmark
저자는 AI 에이전트가 실제 컴포넌트를 사용하는 작업을 수행하도록 했다.
테스트 대상은 다섯 종류의 UI 작업이었다.
각 작업에서는 Primer React의 특정 API를 올바르게 사용해야 했다.
모델은 두 종류를 사용했다.
- Claude Sonnet 5.5
- Claude Haiku 4.5
그리고 세 가지 문서 조건을 비교했다.
- 라이브러리 버전만 안내
- 전체 Flat File 제공
- OKF Bundle 사용
각 조건에서는 15번의 작업을 수행했다.
따라서 두 모델을 합하면 총 90번의 실행이 이루어졌다.
실험 결과는 다음과 같았다.
| 모델 | 문서 조건 | 첫 시도 통과 | 중앙값 기준 예상 비용 |
|---|---|---|---|
| Sonnet 5.5 | 버전 정보만 제공 | 13/15 | $0.028 |
| Sonnet 5.5 | 전체 Flat File | 15/15 | $0.264 |
| Sonnet 5.5 | OKF Bundle | 15/15 | $0.055 |
| Haiku 4.5 | 버전 정보만 제공 | 4/15 | $0.035 |
| Haiku 4.5 | 전체 Flat File | 13/15 | $0.111 |
| Haiku 4.5 | OKF Bundle | 15/15 | $0.032 |
OKF Bundle을 사용한 조건에서는 두 모델 모두 첫 시도에 15개 작업을 통과했다.
특히 Haiku에서는 라이브러리 버전만 제공했을 때보다 통과율이 크게 개선됐다.
비용 측면에서도 차이가 나타났다.
Flat File과 비교하면 OKF Bundle의 중앙값 기준 예상 비용은 다음과 같이 감소했다.
- Sonnet: 약 79% 감소
- Haiku: 약 71% 감소
하지만 실행 시간이 항상 감소한 것은 아니다.
OKF Bundle을 사용하는 경우에는 필요한 문서를 찾고 읽는 작업이 추가되기 때문이다.
저자의 측정에서는 Flat File보다 OKF Bundle의 실행 시간이 다소 길었다.
따라서 토큰 비용과 실행 시간 사이에 트레이드오프가 존재했다.
이번 Benchmark의 한계
이번 결과는 공개된 React 컴포넌트 라이브러리 하나와 다섯 개의 특정 작업을 대상으로 한다.
따라서 모든 디자인 시스템과 모든 AI 모델에서 같은 비율의 비용 절감 효과가 발생한다고 단정할 수 없다.
또한 이번 실험은 OKF의 문서 구조와 Markdown 파일을 여러 개로 분리한 효과를 독립적으로 구분하지 않았다.
예를 들어 같은 정보를 일반적인 Markdown 파일로 나누고 짧은 Index를 제공하더라도 비슷한 결과가 나타날 수 있다.
저자 역시 이러한 비교가 추가로 필요하다고 설명한다.
또한 AI가 생성한 코드의 정확성은 타입 검사와 자체 Contract Checker를 기준으로 측정했다.
실제 사용자 경험과 접근성, 디자인 일관성을 모두 평가한 것은 아니다.
이번 글은 AI 코딩 에이전트에게 최신 컴포넌트 API를 제공하고, 사용한 코드가 실제 디자인 시스템의 규칙을 충족하는지 CI에서 검증하는 구조를 구체적인 코드와 측정 결과로 설명한다.
특히 AI 에이전트의 Context 비용을 줄이면서도 문서의 최신성과 코드의 정확성을 관리하려는 프로젝트에서 참고할 만하다.