- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며 — I/O 2026에서 사라진 단어
- 타임라인 — 발표, 경고음, 취소
- 왜 죽었나 — 시맨틱 인트로스펙션과 hot reload의 충돌
- 성적표 1 — 데이터용 언어 기능: 부분 배송
- 성적표 2 — build_runner: 가장 확실한 배송
- 성적표 3 — augmentations: 미배송
- 죽은 기능이 남긴 흔적들
- 그래서 지금 무엇을 해야 하나
- 마치며
- 참고 자료
들어가며 — I/O 2026에서 사라진 단어
2026년 5월 Google I/O에 맞춰 나온 Dart 3.12 발표문에는 "매크로(macro)"라는 단어가 한 번도 나오지 않습니다. Dart 3.11 발표문(2026년 2월)에도, Dart 3.10 발표문(2025년 11월)에도 없습니다. 정확히 2년 전 I/O 2024에서 "수년간 설계에 투자했다"며 릴리스 발표문의 큰 부분을 할애해 소개했던 기능치고는 완전한 침묵입니다.
무슨 일이 있었는지는 알려져 있습니다 — 매크로는 2025년 1월에 공식 취소되었습니다. 이 글에서 하려는 건 그 사건의 복기가 아니라 사후 검증입니다. 취소문은 "대신 이걸 하겠다"는 약속 세 가지를 남겼고, 그로부터 1년 반이 지난 지금(Flutter 3.44.6 + Dart 3.12.2, 2026년 7월 9일 릴리스 기준)은 그 약속이 지켜졌는지 확인하기 좋은 시점입니다. 검증에는 2차 해설이 아니라 1차 소스만 씁니다 — dart.dev 블로그 원문(사이트 저장소의 마크다운), Dart SDK와 build_runner의 체인지로그, pub.dev 레지스트리 API, GitHub 이슈 상태.
타임라인 — 발표, 경고음, 취소
2024년 5월 14일, Dart 3.4. I/O 2024에서 매크로 프리뷰가 공개됩니다. 첫 매크로는 JSON 직렬화 보일러플레이트를 없애는 @JsonCodable() 하나였고, 계획은 3단계였습니다 — JsonCodable 프리뷰 → 반응이 좋으면 JSON 매크로를 stable로 → 최종적으로 커뮤니티가 자기 매크로를 정의할 수 있게 개방. 흥미로운 대목은 이 글이 데이터 클래스를 직접 언급한다는 점입니다. 데이터 클래스는 Dart 언어 저장소에서 가장 많은 표를 받은 기능 요청인데, 팀은 "무엇이 표준이어야 하는지 의견이 갈린다"며 언어에 내장하는 대신 매크로 시스템으로 커뮤니티가 각자 만들게 하는 쪽을 선택했다고 밝힙니다. 매크로는 처음부터 데이터 문제의 대리 해법이었습니다.
2024년 8월 6일, Dart 3.5. 로드맵 업데이트를 겸한 발표문에서 이미 경고음이 들립니다. 언어·컴파일러 팀 시간의 대부분을 매크로에 쓰고 있다면서도, hot reload 같은 핵심 사용 사례에 회귀를 일으킬 수 있어 신중하게 접근 중이고 "다음 단계를 공유하기까지 여러 분기가 더 필요할 것"이라고 적었습니다. 프리뷰 공개 후 석 달이 채 되기 전에 일정이 "여러 분기 뒤"로 물러난 것입니다.
2025년 1월 29일, 취소. Dart 팀의 Vijay Menon 명의로 An update on Dart macros & data serialization이 올라옵니다. 핵심 문장은 두 개입니다. "큰 기술적 장애물을 하나 풀 때마다 새 장애물이 나타났다", 그리고 "가까운 미래에 매크로를 배송하는 일은 없을 것이다(we will not be shipping macros in the foreseeable future)". 발표에서 취소까지 8개월 반이 걸렸습니다.
왜 죽었나 — 시맨틱 인트로스펙션과 hot reload의 충돌
취소문이 밝힌 이유는 성능도 아니고 인력도 아니고, 설계 목표 자체의 충돌입니다.
Dart 팀은 Rust의 절차적 매크로처럼 프로그램의 구문(syntax)만 보는 매크로로는 목표(데이터 직렬화 같은 문제를 제대로 풀기)에 부족하다고 판단했고, 컴파일 타임에 타입과 선언 구조까지 조회하는 깊은 시맨틱 인트로스펙션을 택했습니다. 문제는 그 선택의 비용이었습니다. 매크로가 프로그램의 의미 정보를 조회한다는 건, 코드가 바뀔 때마다 그 의미에 의존하는 매크로 출력물을 다시 계산해야 한다는 뜻입니다. 취소문의 표현을 빌리면 이 비용이 "stateful hot reload를 뜨겁게(hot) 유지하기 어렵게" 만들었고, 당시 구현은 편집 경험(정적 분석, 코드 완성)과 증분 컴파일(hot reload의 첫 단계) 양쪽 모두를 회귀시키고 있었습니다.
Flutter 개발자 입장에서 이 트레이드는 성립할 수 없는 거래입니다. Dart 팀 스스로 취소문에서 Dart의 정체성을 두 가지로 정의합니다 — 정적 언어 수준의 AOT 성능, 그리고 동적 언어 수준의 개발 사이클(hot reload). 매크로가 아무리 보일러플레이트를 없애 줘도 저장할 때마다 리로드가 굼떠진다면, Flutter가 React Native나 Compose 대비 내세우는 핵심 DX 자산을 갉아먹는 셈입니다. 기회비용을 언급하며 물러선 건 그래서 이해할 수 있는 결정입니다.
취소문은 대신 세 가지를 약속했습니다. (1) 데이터 처리를 위한 "더 맞춤형(bespoke)의 언어 기능들", (2) build_runner 개선, (3) 매크로의 부산물로 프로토타입한 augmentations의 독립 배송. 이제 하나씩 채점합니다.
성적표 1 — 데이터용 언어 기능: 부분 배송
취소 이후의 릴리스에서 작은 언어 기능들이 실제로 나왔습니다. 모두 SDK 체인지로그와 릴리스 발표문에서 확인됩니다.
- null-aware elements — Dart 3.8(2025년 5월 20일)에서 배송. 컬렉션 리터럴 안에서 null이면 통째로 빠지는 원소를 쓸 수 있게 합니다.
- dot shorthands — Dart 3.10(2025년 11월 12일)에서 배송. 문맥에서 타입이 추론될 때
LogLevel.error대신.error라고 쓰는 축약 문법입니다. - private named parameters — Dart 3.12(2026년 5월 20일)에서 배송. private 필드를 named 파라미터로 초기화할 때 강제되던 이니셜라이저 리스트 보일러플레이트를 없앱니다.
- primary constructors — Dart 3.12에서 experimental로 공개(
--enable-experiment=primary-constructors플래그 필요). 그리고 아직 릴리스되지 않은 3.13의 SDK 체인지로그에는 이미 정식 언어 기능으로 기재되어 있습니다.
primary constructors가 이 계보의 본론입니다. 필드 선언과 생성자 파라미터를 클래스 헤더 한 줄로 합칩니다.
// 지금까지의 Dart — 두 필드짜리 클래스에 다섯 줄
class Point {
final int x;
final int y;
Point(this.x, this.y);
}
// primary constructor — 3.12 experimental, 3.13 예정
class Point(final int x, final int y);
다만 채점을 정직하게 하면 "부분 배송"입니다. 매크로가 원래 풀려던 문제 — toJson/fromJson, ==/hashCode/copyWith가 자동으로 생기는 데이터 클래스 — 는 여전히 언어에 없습니다. dart-lang/language#314(Add data classes)는 2017년 10월에 열린 이래 이 글을 쓰는 시점에도 open이고, 추천 수 1,552개로 여전히 최상위권 요청입니다. 지금까지 배송된 건 보일러플레이트를 줄이는 문법이지, 직렬화 코드를 생성해 주는 무언가가 아닙니다. 그 일은 아래의 코드젠이 계속 맡습니다.
성적표 2 — build_runner: 가장 확실한 배송
매크로의 대안이 결국 "build_runner를 빠르게"였으므로, 여기가 제일 중요한 항목입니다. 그리고 여기는 숫자로 확인됩니다.
pub.dev 레지스트리 API의 발행 이력을 그대로 옮기면, 취소 전 build_runner는 사실상 유지보수 모드였습니다. 2.4.0(2023년 1월 18일)부터 2.4.15(2025년 2월 11일)까지 25개월간 릴리스 16개, 전부 패치 버전이고 마이너 범프가 하나도 없습니다. 취소 후가 변곡점입니다 — 2.5.0(2025년 6월 16일)부터 2.15.2(2026년 7월 13일)까지 13개월간 릴리스 30개, 마이너 라인만 11개가 나왔습니다. 취소문이 공언한 투자가 레지스트리 데이터에 그대로 찍혀 있는 셈입니다.
내용도 패치 수준이 아닙니다. build_runner 체인지로그 기준으로 2026년 상반기에만:
- 2.13.0(2026년 3월) — "작은 초기 빌드 1.4배에서 큰 증분 빌드 4배 사이의 속도 향상". 벤치마크 전문은 릴리스 PR(dart-lang/build#4405)에 공개되어 있습니다.
- 2.14.0(2026년 4월) — 분석용 파일 관리 개선으로 "증분 빌드 2배 추가 향상". 빌더 컴파일이 JIT에서 AOT 기본으로 바뀌었고(
dart:mirrors를 쓰는 빌더는 JIT로 폴백), 초기 기동은 느려지는 대신 이후 빌드가 빨라지는 트레이드를 명시했습니다. - 2.15.0(2026년 4월) — 기본 메모리 사용량이 개선되었다며
--low-resources-mode플래그 자체를 제거.
숫자에는 라벨을 붙여야 합니다. 위의 1.4배·4배·2배는 모두 Dart 팀 자체 벤치마크 수치입니다. 측정 조건은 해당 릴리스 PR의 벤치마크 스위트이고, 여러분의 코드베이스 — 빌더 조합, 패키지 수, 워크스페이스 구조 — 에서 같은 배수가 나온다는 보장은 없습니다. 4배라는 상한은 "큰 증분 빌드"라는 조건이 붙은 값입니다. 독립 재현 벤치마크는 아직 본 적이 없습니다. 그래도 방향 자체는 체인지로그 수십 개 항목이 일관되게 가리키고 있고, 개선의 존재까지 의심할 이유는 없습니다.
성적표 3 — augmentations: 미배송
취소문이 "매크로에서 프로토타입한 기능 중 독자적으로 가치가 있다, 독립 배송을 목표로 한다"고 했던 augmentations(한 선언을 다른 파일에서 증강하는 기능 — 코드젠 출력물을 part 파일보다 매끄럽게 붙이는 기반)는, 이 글을 쓰는 시점 기준 어느 릴리스에도 실리지 않았습니다. 추적 이슈 dart-lang/language#4154는 여전히 open이고(2026년 2월에 마지막 갱신), 미출시 3.13 구간까지의 SDK 체인지로그에도 augmentation 항목은 없습니다. 세 약속 중 유일하게 아무것도 도착하지 않은 항목입니다.
참고로 build_runner 개선의 상위 추적 이슈(dart-lang/build#3800, "Faster dev cycle")도 아직 open입니다 — 배송이 진행 중이라는 뜻이지, 끝났다는 뜻은 아닙니다.
죽은 기능이 남긴 흔적들
취소가 얼마나 철저했는지는 부산물 정리에서 보입니다. 전부 지금 확인 가능한 상태입니다.
- pub.dev의
macros패키지(0.0.1에서 멈춤)와 JsonCodable을 담았던json패키지(0.20.4, 2024년 12월이 마지막)는 둘 다 discontinued 마크가 붙었습니다. - 문서 페이지였던 dart.dev/language/macros 는 이제 취소 블로그 글로 301 리다이렉트됩니다. 기능 문서의 URL이 그 기능의 부고 기사로 연결되는, 흔치 않은 풍경입니다.
한편 매크로가 대체하려던 것들은 멀쩡히 살아 있습니다. pub.dev 기준 json_serializable은 6.14.0(2026년 5월 15일), freezed는 3.2.5(2026년 2월 3일)로 계속 릴리스 중입니다. 2026년의 Dart 데이터 직렬화는 여전히 코드젠이고, 달라진 건 그 코드젠을 돌리는 엔진이 빨라졌다는 점입니다.
그래서 지금 무엇을 해야 하나
매크로를 기다리며 미뤄 둔 결정이 있다면 끝내십시오. 공식 입장은 "foreseeable future에 없다"이고, 최근 세 번의 릴리스 발표문(3.10·3.11·3.12)에서 매크로는 언급조차 되지 않습니다. 장기 메타프로그래밍 탐구 이슈(#1482)가 열려 있긴 하지만, 로드맵에 있는 건 아무것도 없습니다.
build_runner를 최신으로 올리는 건 값싼 이득입니다. 2.4.x에 머물러 있는 프로젝트라면 2.15.x까지 사이에 성능 개선이 여러 층 쌓여 있습니다. 다만 2.14.0부터 AOT 컴파일이 기본이라 첫 기동이 느려질 수 있고, dart:mirrors 의존 빌더가 있으면 JIT 폴백이 일어난다는 점은 알고 올리는 게 좋습니다.
primary constructors는 아직 켜지 마십시오. 3.12에서는 experimental 플래그이고, experimental 기능은 릴리스 사이에 문법이 바뀔 수 있습니다. 3.13 체인지로그에 정식 기재된 건 맞지만 3.13은 아직 릴리스되지 않았습니다 — 미출시 체인지로그는 계획이지 약속이 아닙니다.
freezed/json_serializable 스택을 걷어낼 이유는 없습니다. 언어가 데이터 클래스를 내장하는 날이 오기 전까지(#314는 2017년부터 열려 있습니다), 코드젠은 Dart의 데이터 스토리 그 자체입니다. Flutter 생태계 전반에서 이 스택이 차지하는 위치는 크로스플랫폼 비교 글에서 다룬 그대로입니다.
마치며
기능 취소는 보통 조용히 일어납니다. 이슈가 몇 년 방치되다 닫히고, 문서가 슬그머니 사라지는 식으로. Dart 매크로 취소가 복기할 가치가 있는 건 그 반대였기 때문입니다 — 이유(시맨틱 인트로스펙션의 컴파일 타임 비용이 hot reload와 양립 불가)를 기술적으로 설명했고, 대안 세 가지를 명시했고, 그중 둘은 1년 반 뒤 릴리스와 레지스트리 데이터로 확인 가능한 형태로 배송되고 있습니다.
동시에 채점표는 미완입니다. augmentations는 도착하지 않았고, 데이터 클래스는 여전히 이슈 트래커의 1위 요청이며, build_runner의 속도 수치는 아직 팀 자체 측정뿐입니다. 매크로의 죽음이 남긴 교훈이 있다면 이것일 겁니다 — hot reload는 Dart가 어떤 언어 기능과도 바꾸지 않는 불가침 자산이라는 것, 그리고 그 제약 아래에서 Dart의 메타프로그래밍은 당분간 "더 빠른 코드젠"이라는 답에 머문다는 것.
참고 자료
- An update on Dart macros & data serialization — 취소 공지 원문 (2025-01-29)
- Announcing Dart 3.4 — 매크로 프리뷰 발표 (2024-05-14)
- Announcing Dart 3.5, and an update on the Dart roadmap (2024-08-06)
- Announcing Dart 3.10 — dot shorthands, build hooks (2025-11-12)
- Announcing Dart 3.11 (2026-02-11)
- Announcing Dart 3.12 — private named parameters, primary constructors experimental (2026-05-20)
- Dart SDK CHANGELOG — 3.12.0 및 미출시 3.13.0 항목
- build_runner CHANGELOG — 2.13.0/2.14.0/2.15.0 성능 항목
- dart-lang/language#314 — Add data classes (open)
- dart-lang/language#4154 — Augmentations (open)
- dart-lang/build#3800 — Faster dev cycle (open)
- Flutter SDK 릴리스 아카이브 JSON — 3.44.6/Dart 3.12.2 확인용