REPO DEEP DIVE · 2026-07-29 · LUCIDE-ICONS/LUCIDE · 아이콘 원본 하나가 10개 프레임워크 패키지가 되기까지

lucide-icons/lucide 딥다이브
SVG 파일 1,756개가 소스이자 전부인 아이콘 세트

Lucide는 웹·앱 화면에서 흔히 보는 아이콘(작은 그림 기호)들을 모아놓은 오픈소스 라이브러리다. 원래 Feather Icons라는 인기 아이콘 세트가 유지보수를 멈추자, 커뮤니티가 그대로 포크(복제)해 이어받으며 시작됐다.

이 레포에서 진짜로 짜여 있는 것은 놀랍도록 단순하다. 아이콘 하나당 SVG 파일 한 장 + 메타데이터 JSON 한 장, 그게 전부다(icons/*.svg, icons/*.json). 그런데 이 단순한 원본에서 React·Vue·Svelte·Angular·Solid·Preact·React Native·Astro·순수 자바스크립트·정적 SVG/폰트까지 10개가 넘는 프레임워크별 패키지가 자동으로 "찍혀 나온다." 사람이 각 프레임워크용 코드를 손으로 짜는 게 아니라, 빌드 스크립트가 SVG를 읽어 각 프레임워크에 맞는 컴포넌트 코드를 생성하는 구조다.

(저장소 lucide-icons/lucide · 라이선스 ISC(Feather 유래 아이콘 일부는 MIT 병기) · 아이콘 수 1,756개(대기 중인 lab/ 후보 356개 별도) · 카테고리 42종 · pnpm 모노레포(패키지 14개) · Node ≥24.11 · 최신 커밋 4aec3f8(2026-07-25) · npm 실배포 버전 1.27.0 · 정리 기준일 2026-07-29)
목차
  1. 한 줄 정체
  2. 왜 지금 뜨는가
  3. 무엇을 해결하나
  4. 전체 구조
  5. 핵심 설계·동작 원리
  6. 기술 스택·의존성
  7. 설치·요구사항
  8. 실제 사용 흐름
  9. 함정·오해 방지
  10. 대안 비교
  11. 정리 · 누가 쓰면 좋은가

1한 줄 정체

"화면 속 작은 그림 기호" 모음 — 그 이상도 이하도 아니다

Lucide는 아이콘 라이브러리다. 우리가 앱에서 매일 보는 돋보기(검색), 톱니바퀴(설정), 하트(좋아요) 같은 작은 선 그림들을 일관된 스타일로 통일해서 모아 놓고, 개발자가 코드 한 줄로 가져다 쓸 수 있게 포장해 놓은 프로젝트다. AI도 서버도 아니고, 순수하게 "그림 파일 + 그걸 각 프로그래밍 언어 코드로 바꿔주는 자동화 도구"다.

실제로 저장소를 열어 보면 핵심 폴더는 icons/ 하나뿐이다. 그 안에 아이콘 이름별로 activity.svg(그림 자체)와 activity.json(이름·태그·카테고리 같은 부가 정보)이 쌍으로 1,756벌 들어 있다. 이 폴더가 유일한 원본(source of truth)이고, packages/ 아래 있는 React용·Vue용·Svelte용 패키지들은 전부 이 원본을 재료 삼아 빌드 시점에 자동 생성된 결과물이다.

한 줄 비유

"원본 도장(SVG)" 하나로 "여러 나라 말(프레임워크)"의 설명서를 자동 번역해 찍어내는 인쇄소

아이콘 디자이너는 선 그림 원본(도장) 하나만 정성껏 새긴다. 그 다음은 인쇄소(빌드 스크립트)의 일이다. 인쇄소는 같은 도장을 찍되, React라는 언어로 된 사용설명서, Vue라는 언어로 된 사용설명서… 이런 식으로 프레임워크별 "번역판"을 자동으로 찍어낸다.

즉 디자이너는 그림 하나만 그리면 되고, "이 그림을 리액트 컴포넌트로 바꿔라", "이 그림을 Vue 컴포넌트로 바꿔라" 같은 반복 작업은 전부 기계가 대신한다. 사람이 10번 다시 그릴 필요가 없다.

용어
SVG (Scalable Vector Graphics)
점·선·곡선의 좌표로 그림을 표현하는 파일 형식. 사진(픽셀)과 달리 아무리 확대해도 계단 현상 없이 매끈하게 보인다. 아이콘처럼 작고 단순한 그림에 널리 쓰인다.
용어
모노레포 (monorepo)
서로 관련된 여러 개의 패키지(라이브러리)를 하나의 저장소 안에 함께 두고 관리하는 방식. Lucide는 packages/ 폴더 안에 React용·Vue용 등 14개 패키지를 한 저장소에서 같이 관리한다.

2왜 지금 뜨는가

"죽은 프로젝트를 살린 포크"가 업계 표준이 되기까지

Lucide 자체는 신생 기술이 아니라 2020년에 시작된 포크(fork, 원본 프로젝트를 복제해 독자적으로 이어가는 것)다. 그런데도 여전히, 그리고 갈수록 더 많이 쓰이는 데는 이유가 있다.

① 원조(Feather Icons)가 멈췄을 때, 커뮤니티가 "그대로 이어받았다"

Lucide의 LICENSE 파일에는 지금도 airplay, calendar, search 등 특정 아이콘 목록이 "Feather 프로젝트에서 유래했다"고 명시돼 있고, 그 아이콘들에는 Feather 원작자 Cole Bemis의 MIT 라이선스가 병기돼 있다. 즉 Lucide는 "Feather를 베낀 것"이 아니라 "멈춰버린 원조를 커뮤니티가 공식적으로 이어받아 계속 키운 것"이다. 이런 배경 덕에 초기부터 많은 기존 Feather 사용자가 자연스럽게 옮겨왔다.

② shadcn/ui 같은 인기 UI 킷의 "기본 아이콘"으로 채택됨

최근 몇 년 사이 폭발적으로 쓰이는 React 컴포넌트 모음 shadcn/ui를 비롯해, 여러 스타터 템플릿·보일러플레이트가 Lucide를 기본 아이콘 세트로 지정했다. 한 인기 도구가 채택하면, 그 도구를 쓰는 수많은 프로젝트가 자동으로 Lucide도 함께 설치하게 된다 — "기본값의 힘"이다.

③ 프레임워크를 가리지 않는 "전방위 패키지" 전략

packages/ 폴더를 보면 React·Vue·Svelte·Angular·Solid·Preact·React Native·Astro까지 사실상 프론트엔드 생태계 전체를 커버한다. 어떤 프레임워크로 시작하든 "Lucide는 있다"는 확신을 주기 때문에, 팀이 기술 스택을 바꿔도 아이콘 세트는 그대로 유지할 수 있다.

경쟁 지형에서의 위치
"일관성 있는 선 스타일" + "커뮤니티 주도 개방성"

Font Awesome처럼 상업적 색이 짙거나, Material Symbols처럼 구글이라는 한 회사에 종속된 세트와 달리, Lucide는 중립적인 커뮤니티 프로젝트다. 누구나 새 아이콘을 제안하고 병합될 수 있고, 실제로 지금도 매주 새 아이콘이 추가된다(직전 커밋도 feat(icons): add layout-freeform이었다).

3무엇을 해결하나

"아이콘 하나를 프레임워크마다 다시 만드는" 반복 노동 제거

아이콘 라이브러리가 없다면 개발자는 매번 아이콘을 PNG나 SVG로 하나하나 내려받아 프로젝트에 끼워 넣어야 한다. 색을 바꾸려면 SVG 코드를 열어 직접 수정해야 하고, 크기를 바꾸면 화질이 깨지거나 레이아웃이 어긋나기도 한다. 게다가 팀 안에서 어떤 사람은 동그란 스타일, 어떤 사람은 각진 스타일 아이콘을 섞어 쓰면 화면이 중구난방으로 보인다.

Lucide가 실제로 해결하는 문제는 세 가지로 요약된다.

비유

레고 블록 회사가 "빨간 2x4 블록" 하나의 금형(원본)만 정교하게 만들어두면, 그 블록으로 자동차 세트에도 성 세트에도 똑같이 끼워 쓸 수 있는 것과 같다. Lucide는 아이콘이라는 블록의 "금형"을 표준화해, 어떤 프레임워크라는 "세트"에 꽂아도 모양이 어긋나지 않게 만든다.

4전체 구조

pnpm 모노레포 — icons/ 원본 · tools/ 빌드 엔진 · packages/ 결과물 14종

저장소는 pnpm 워크스페이스 모노레포(packages/*, tools/*, docs)로 구성돼 있다. 전체 그림을 셋으로 나누면 이렇다.

┌────────────────────────────────────────────────────────────────┐ │ LUCIDE 저장소 전체 지도 │ └────────────────────────────────────────────────────────────────┘ [1] icons/ ★ 유일한 원본 (source of truth) activity.svg · activity.json ×1,756벌 └ 24x24 캔버스 · stroke-width 2 · round cap/join [2] tools/build-icons + scripts/generate ├ cli.ts # svg → icons 객체로 파싱 ├ render/renderIconsObject.ts ├ building/generateIconFiles.ts # 아이콘별 소스 파일 생성 └ building/generateDynamicImports.ts [3] packages/* # 빌드 결과물 — "생성된 코드" ├ lucide-react ├ vue(@lucide/vue) ├ svelte(@lucide/svelte) ├ lucide-solid ├ lucide-preact ├ lucide-react-native ├ angular ├ astro ├ lucide-static ├ lucide (바닐라 JS) ├ icons(@lucide/icons, 트리셰이킹 데이터) └ shared(공통 유틸)

각 패키지 폴더(packages/lucide-react/src/icons/ 등) 안의 .ts/.svelte/.vue 파일들은 사람이 직접 짜서 커밋한 코드가 아니다. package.jsonbuild:icons 스크립트가 매 빌드마다 icons/*.svg를 읽어 새로 찍어낸다. 즉 "코드가 있는 폴더"처럼 보이지만 실제로는 생성된 산출물이 커밋에 섞여 있을 뿐이다 — 이 구조를 모르면 "왜 아이콘 파일 코드가 다 똑같이 생겼지?"에서 헤맬 수 있다.

5핵심 설계·동작 원리

"SVG 한 장 → 파싱 → 프레임워크별 템플릿에 꽂기" — 코드 생성 파이프라인 실물 추적

이 레포에서 가장 배울 만한 부분은 "디자인 원본 하나에서 코드를 자동 생성하는 파이프라인"이다. 실제 소스 파일을 순서대로 따라가 보자.

① 원본 확인 — icons/activity.svg + activity.json

아이콘 하나는 SVG 파일과 JSON 메타데이터 파일이 이름이 같은 쌍으로 존재한다. 실제 icons/activity.svg를 열어보면 다음과 같다.

<svg
  xmlns="http://www.w3.org/2000/svg"
  width="24"
  height="24"
  viewBox="0 0 24 24"
  fill="none"
  stroke="currentColor"
  stroke-width="2"
  stroke-linecap="round"
  stroke-linejoin="round"
>
  <path d="M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36..." />
</svg>

짝을 이루는 activity.json에는 그림 정보가 아니라 이름·기여자·태그·카테고리만 들어 있다. 그림(형태)과 의미(메타데이터)를 파일 두 장으로 확실히 분리해 둔 것이다.

② 빌드 엔진 — tools/build-icons가 SVG를 "데이터"로 바꾼다

각 패키지의 package.json에는 build:icons라는 스크립트가 있고, 실제로 lucide-react 패키지는 다음처럼 정의돼 있다(직접 확인한 원문).

"build:icons": "build-icons --output=./src
  --templateSrc=./scripts/exportTemplate.mts
  --renderUniqueKey --withAliases --withDynamicImports
  --separateAliasesFile --iconFileExtension=.ts
  --exportFileName=index.ts"

이 명령이 실행하는 tools/build-icons/cli.ts의 핵심 흐름은 이렇다. 함수 이름까지 그대로 인용한다.

  1. readSvgDirectory(ICONS_DIR)icons/ 폴더의 모든 SVG 파일 목록을 읽는다.
  2. renderIconsObject(svgFiles, ICONS_DIR, renderUniqueKey) — 각 SVG의 <path>·<circle> 같은 태그를 파싱해, "[태그이름, 속성객체]" 배열(IconNode)이라는 프레임워크 중립적인 데이터 구조로 바꾼다. 이 시점부터는 더 이상 텍스트 SVG가 아니라 자바스크립트 객체다.
  3. templateSrc로 지정된 패키지별 템플릿 함수(예: packages/lucide-react/scripts/exportTemplate.mts)를 불러온다. 이 템플릿이 "이 데이터를 어떤 프레임워크 문법으로 찍어낼지"를 결정하는 핵심이다.
  4. generateIconFiles(...) — 아이콘 1,756개 각각에 대해 템플릿 함수를 호출해 src/icons/activity.ts 같은 실제 소스 파일을 써낸다.
  5. withAliases·withDynamicImports 옵션이 켜져 있으면 별칭(구명·별명) 파일과 동적 import용 맵(dynamicIconImports)도 함께 생성한다.
  6. generateExportsFile(...) — 마지막으로 1,756개 아이콘을 전부 다시 내보내는 index.ts(배럴 파일)를 만든다.
비유

SVG 원본은 재료(밀가루 반죽)고, renderIconsObject는 그 반죽을 "표준 규격 데이터"로 다듬는 손질 과정이다. 그리고 templateSrc(패키지별 템플릿)는 붕어빵 틀이다. 같은 반죽이라도 어떤 틀에 넣느냐에 따라 붕어빵(React 컴포넌트)이 되기도, 크루아상(Vue 컴포넌트)이 되기도 한다. 반죽은 하나, 틀만 프레임워크마다 다르다.

③ React 패키지의 실제 "틀" — exportTemplate.mts

실제로 packages/lucide-react/scripts/exportTemplate.mts는 다음과 같이 각 아이콘 파일을 위한 문자열 템플릿을 반환한다(원문 그대로).

export default defineExportTemplate(async({
  componentName, iconName, children, getSvg, deprecated, deprecationReason,
}) => {
  const svgContents = await getSvg();
  const svgBase64 = base64SVG(svgContents);
  return `
import createLucideIcon from '../createLucideIcon';
import { IconNode } from '../types';

export const __iconNode: IconNode = ${JSON.stringify(children)}

const ${componentName} = createLucideIcon('${iconName}', __iconNode);
export default ${componentName};
`;
});

실제로 생성되는 src/icons/activity.ts 파일은 사람이 짠 게 아니라, 위 템플릿 함수가 children(파싱된 SVG 데이터)을 JSON.stringify로 그대로 박아 넣은 결과물이다. 그리고 그 파일이 부르는 createLucideIcon('activity', __iconNode)(packages/lucide-react/src/createLucideIcon.ts)가 진짜 React 컴포넌트를 만든다 — forwardRef로 감싸고, lucide-{kebab-case 이름} 클래스를 자동으로 붙인다.

렌더링 최종 단계인 Icon.ts에서는 size·color·strokeWidth 같은 props를 받아 진짜 <svg> 엘리먼트를 만든다. 흥미로운 디테일 하나 — absoluteStrokeWidth 옵션을 켜면 calculatedStrokeWidth = strokeWidth * 24 / size 공식으로 아이콘을 키워도 선 굵기 비율이 뭉개지지 않게 자동 보정한다.

④ 프레임워크마다 "틀"만 다르고 재료·조립 로직은 같다

패키지템플릿 결과물비고
lucide-react.tscreateLucideIcon() 호출forwardRef 기반 컴포넌트
@lucide/vue.ts — Vue용 render 함수renderUniqueKey 옵션(Vue의 key 요구사항 대응)
@lucide/svelte.svelte 컴포넌트 파일아이콘 파일 확장자 자체가 .svelte로 다름
lucide-static.ts + 순수 SVG 문자열프레임워크 없이 마크업만 필요할 때
@lucide/icons이름+노드 데이터만(컴포넌트 없음)다른 패키지가 이 데이터를 소비하는 기반 데이터 패키지

이 표에서 보듯, "SVG를 파싱해 IconNode 데이터로 만드는 공통 엔진"tools/build-icons 하나뿐이고, 각 패키지는 --templateSrc 인자로 자기 문법에 맞는 출력 함수만 갈아 끼운다. 새 프레임워크를 지원하고 싶다면 이론적으로 템플릿 함수 하나만 새로 짜면 된다 — 실제로 @lucide/icons는 "컴포넌트가 아니라 데이터"를 내보내, 커뮤니티가 자체적으로 지원되지 않는 프레임워크용 통합을 만들 수 있게 열어둔 것이라고 공식 문서가 밝힌다.

용어
IconNode
SVG의 각 태그(path, circle 등)를 [태그이름, 속성객체] 튜플 배열로 표현한, Lucide 내부의 프레임워크 중립 데이터 형식. 모든 패키지가 최종적으로 이 형식을 소비한다.
용어
트리셰이킹 (tree-shaking)
번들러(코드를 하나로 묶는 도구)가 실제로 쓰이지 않는 코드를 잘라내는 최적화. 아이콘을 하나씩 개별 파일로 만들어두면, 안 쓰는 1,755개 아이콘은 최종 결과물에서 제거될 수 있다.

⑤ 디자인 규칙은 "코드"가 아니라 "사람 + 도구"로 지켜진다

많은 사람이 "24×24 그리드, 선 굵기 2px, 둥근 끝처리" 같은 규칙이 자동 CI(지속적 통합) 검사로 딱딱 걸러질 거라고 짐작하지만, 실제 코드를 보면 다르다. docs/contribute/icon-design-guide.md에 14개 조항으로 규칙이 문서화돼 있고, 실제 자동화는 scripts/optimizeSvgs.mts(processSvg 함수)가 SVGO로 SVG를 최적화하고 기본 속성(width/height/stroke-width 등)을 강제로 덮어씌우는 것, 그리고 lint:icons(prettier로 SVG 포맷 검사)와 lint:json:icons(JSON 스키마 검증)뿐이다.

함정
"픽셀 그리드 규칙이 CI로 검증된다"는 오해

실제로는 선 굵기·라운드 캡 같은 속성값은 스크립트가 강제로 고정하지만, "옵티컬 볼륨이 원·정사각형과 비슷한가", "곡선이 매끄럽게 이어지는가" 같은 시각적 품질 규칙은 자동 검사 대상이 아니다. 이건 기여자가 Lucide Studio라는 웹 에디터로 직접 맞추고, PR 리뷰어(사람)가 눈으로 검토해서 지켜진다. "CI가 다 걸러줄 것"이라 믿고 대충 그려 올리면 리뷰에서 반려된다.

6기술 스택·의존성

pnpm 워크스페이스 · SVGO · Rollup · 패키지별 프레임워크 런타임
레이어기술 / 도구역할
모노레포 관리pnpm workspace(pnpm-workspace.yaml)packages/*·tools/*·docs를 한 저장소에서 관리
SVG 파싱/최적화svgson, svgo, prettierSVG ↔ 객체 변환, 불필요한 속성 제거, 포맷 통일
코드 생성자체 제작 @lucide/build-icons, @lucide/helpersSVG → 프레임워크별 소스 파일 생성 엔진(이 저장소 고유 도구)
번들링Rollup(대부분 패키지), Vite(문서 사이트)생성된 소스를 CJS/ESM 배포용으로 묶음
검증ajv-cli(JSON 스키마), cspell, ESLint, Vitest메타데이터 스키마 검증, 철자 검사, 코드 린트, 유닛 테스트
문서 사이트VitePress(docs/)lucide.dev 정적 문서 생성
패키지별 런타임React 18/19, Vue 3, Svelte, SolidJS, Preact, Angular, Astro각 패키지의 peerDependencies로만 존재 — 이 저장소 자체는 특정 프레임워크에 종속되지 않음

주목할 점은 패키지별로 프레임워크 런타임이 peerDependencies(직접 설치하지 않고 사용자 프로젝트의 버전을 빌려 쓰는 의존성)로만 선언돼 있다는 것이다. 예를 들어 lucide-reactreact: "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"처럼 폭넓은 버전대를 허용해, React 16을 쓰는 오래된 프로젝트에서도 최신 아이콘을 그대로 쓸 수 있게 열어둔다.

7설치·요구사항

패키지 매니저로 설치 한 줄 — 저장소를 빌드하려면 Node 24.11+ · pnpm

일반 사용자(그냥 아이콘을 쓰고 싶은 개발자)는 이 레포를 클론할 필요조차 없다. 원하는 프레임워크 패키지 하나만 설치하면 된다.

# React 프로젝트
npm install lucide-react

# Vue 3 프로젝트 (최신 패키지명)
npm install @lucide/vue

# 프레임워크 없이 순수 SVG/폰트만
npm install lucide-static
항목요구사항
일반 사용(패키지 설치)해당 프레임워크가 요구하는 Node 버전 이상이면 충분. 특별한 하드웨어 요구 없음
이 저장소 자체를 빌드할 때Node ≥24.11.1, pnpm 11.16.0(packageManager 필드로 고정) 필요
클론 후 준비pnpm installpnpm build(전 패키지) 또는 pnpm lucide-react build(개별 패키지)
아이콘 기여(디자인)Figma / Illustrator / Inkscape / Affinity Designer 중 하나 + Lucide Studio(웹 기반 SVG 정렬 도구)
가볍게 시작하는 법
저장소를 몰라도, 설치 한 줄이면 충분

아이콘을 "쓰기만" 할 사람은 이 문서의 5번 섹션 같은 내부 구조를 몰라도 된다. npm install lucide-react(또는 원하는 프레임워크 패키지) 한 줄로 끝난다. 내부 구조는 "내가 왜 특정 방식으로 import해야 하는지"를 이해하고 싶을 때만 필요하다(9번 섹션 참고).

8실제 사용 흐름

설치 → import → props로 커스터마이즈 — 세 단계면 끝

가장 흔한 사용 사례인 React를 기준으로 실제 사용 흐름을 그대로 따라가 본다.

단계 1

설치

npm install lucide-react
단계 2

아이콘 이름 그대로 import

import { Camera } from 'lucide-react';

function App() {
  return <Camera />;
}

파일 이름 camera.svg가 파스칼케이스 컴포넌트 Camera로 바뀐 것이다. 이 매핑을 만드는 게 5번 섹션에서 본 generateExportsFile이다.

단계 3

props로 색·크기·굵기 조정

<Camera size={48} color="red" strokeWidth={1} />

새 이미지 파일을 준비할 필요 없이, 같은 SVG 데이터를 런타임에 다른 속성으로 다시 그리는 것뿐이다. 기본값은 size=24 · color=currentColor · strokeWidth=2 — 즉 아무 props 없이 쓰면 디자인 가이드가 정한 원본 그대로 렌더링된다.

필요할 때만

수백 개 이름을 동적으로 골라 써야 한다면 — DynamicIcon

import { DynamicIcon } from 'lucide-react';

// name이 서버에서 온 문자열이라 미리 import를 정해둘 수 없을 때
<DynamicIcon name="camera" />

CMS(콘텐츠 관리 시스템)에서 아이콘 이름을 문자열로 저장해두고 나중에 렌더링해야 하는 경우처럼, 아이콘 이름을 코드 작성 시점에 알 수 없을 때 쓴다. 필요한 아이콘만 그때그때 불러오는(lazy-load) 구조라 번들에는 실제로 쓰는 것만 남는다.

9함정·오해 방지

번들 크기 폭증 · 옛 패키지명 · package.json의 거짓 버전 번호

함정 ① "그냥 배럴 파일에서 import하면 트리셰이킹이 알아서 될 것" — 항상 그렇지는 않다

import { Camera } from 'lucide-react'처럼 배럴 파일(barrel file, 여러 모듈을 한곳에서 다시 내보내는 진입점 파일)에서 가져오면, 번들러가 트리셰이킹(안 쓰는 코드 제거)을 잘 해줄 거라 기대하기 쉽다. 하지만 공식 문서(docs/guide/react-native/advanced/optimizations.md)가 명시적으로 경고한다.

함정
React Native 웹 빌드에서 아이콘 전체가 번들에 들어갈 수 있다

Expo로 웹용 빌드를 만들 때 쓰는 Metro 번들러는 배럴 파일의 트리셰이킹을 안정적으로 못 한다. 그 결과 import { Camera } from 'lucide-react-native' 한 줄만 써도 1,756개 아이콘 전부가 최종 번들에 딸려 들어갈 수 있다. 공식 해결책은 import Camera from 'lucide-react-native/icons/camera'처럼 아이콘 파일을 개별 경로로 직접 import하는 것이다.

이 문제가 React Native 전용은 아니다. 오래된 번들러 설정이나 트리셰이킹이 약한 환경이라면 다른 프레임워크 패키지에서도 같은 증상이 날 수 있다 — "import 몇 줄 썼는데 번들이 갑자기 커졌다"는 리포트가 나오면 이 지점을 먼저 의심해야 한다.

함정 ② 튜토리얼에서 본 패키지명이 이미 옛날 이름일 수 있다

함정
lucide-vue-next · lucide-svelte · lucide-angular는 지금은 폐기(deprecated) 이름

인터넷의 많은 블로그·유튜브 튜토리얼이 예전 패키지명인 lucide-vue-next, lucide-svelte, lucide-angular를 그대로 설치하라고 안내한다. 하지만 실제로 npm에서 확인하면 이 패키지들은 "Please use @lucide/vue instead" 같은 폐기 안내와 함께 각각 @lucide/vue, @lucide/svelte, @lucide/angular로 이름이 바뀌었다. 옛 이름도 당장 설치는 되지만 더 이상 업데이트되지 않는 버전에 고정될 위험이 있다.

함정 ③ 저장소 안 package.json의 버전 번호를 믿지 말 것

이 저장소를 클론해서 packages/lucide-react/package.json을 열어보면 버전이 0.0.1로 적혀 있다(실제로 확인한 값). 하지만 npm에 배포된 실제 버전은 이 글 작성 시점 기준 1.27.0이다. 왜 이런 차이가 날까 — .github/workflows/release.yml을 보면, 버전은 소스 코드에 미리 적어두는 게 아니라 "릴리스 시 git 태그(v1.27.0 등)를 기준으로 pnpm version ... --no-git-tag-version 명령이 그 순간 덮어쓰는 값"이다. 즉 진짜 버전의 근원(source of truth)은 저장소 파일이 아니라 릴리스 워크플로가 참조하는 git 태그다.

함정 ④ "코드가 있는 폴더"처럼 보이지만 커밋에는 생성된 파일이 섞여 있다

packages/lucide-react/src/icons/*.ts 같은 파일들을 GitHub에서 보면 사람이 짠 코드처럼 보이지만, 5번 섹션에서 봤듯 이건 빌드 스크립트의 산출물이다. 이 폴더의 코드를 직접 고쳐도 다음 빌드에서 덮어써진다 — 아이콘 자체를 고치고 싶다면 src/icons/가 아니라 icons/*.svg 원본을 고쳐야 한다.

함정 ⑤ Feather와 100% 호환된다고 생각하기 쉽지만, 이름이 바뀐 아이콘이 있다

Feather에서 넘어온 아이콘들은 Lucide의 이름 규칙(예: "용도가 아니라 형태로 이름 짓기" — save 대신 floppy-disk)을 적용받아 일부는 이름이 바뀌었다. Feather 시절 코드를 그대로 복사해 붙이면 import가 실패할 수 있다.

10대안 비교

Feather · Heroicons · Phosphor · Tabler — 어디가 다른가
세트특징Lucide와 차이
Feather IconsLucide의 원조. 아이콘 수가 적고(약 280개) 유지보수가 매우 느림Lucide는 사실상 "활발히 관리되는 Feather 확장판"에 가깝다. 신규 프로젝트라면 Lucide가 아이콘 수·최신성 모두 우위
HeroiconsTailwind CSS 팀이 만듦. outline/solid 2가지 스타일, 아이콘 수는 상대적으로 적음(약 300개대)Tailwind 생태계와 궁합은 좋지만 아이콘 종류·프레임워크 지원 폭은 Lucide가 훨씬 넓음
Phosphor Iconsthin/light/regular/bold/fill/duotone 등 6가지 굵기 변형 제공. 아이콘 수 매우 많음스타일 다양성은 Phosphor가 앞서지만, 그만큼 배포 용량도 커짐. Lucide는 "하나의 통일된 스타일"에 집중
Tabler IconsLucide와 비슷하게 24×24·2px 선 스타일. 아이콘 수도 매우 많음(수천 개대)디자인 철학이 가장 비슷한 경쟁자. 어느 쪽을 골라도 "선 굵기 통일 스타일"이라는 결과는 비슷하며, 취향·생태계 지원(shadcn/ui 등)이 선택 기준이 되는 경우가 많음
비유

이들은 모두 "선으로 그린 단순한 그림 아이콘"이라는 같은 장르 안의 서로 다른 글꼴(폰트) 브랜드와 비슷하다. Helvetica냐 Inter냐처럼, 기능은 비슷해도 미묘한 선 두께·모서리 처리 느낌이 다르고, 한 프로젝트 안에서는 한 브랜드만 골라 통일해서 쓰는 것이 핵심이다. 아이콘 세트를 섞어 쓰면 폰트를 섞어 쓴 것처럼 화면이 어색해진다.

11정리 · 누가 쓰면 좋은가

"쓰는 사람"에게는 설치 한 줄, "배우는 사람"에게는 코드 생성 파이프라인 교과서

Lucide는 화려한 신기술이 아니라, "원본 하나 → 여러 결과물 자동 생성"이라는 아주 오래되고 검증된 소프트웨어 공학 패턴을 아이콘이라는 소재로 아주 깔끔하게 구현한 사례다. 핵심을 세 문장으로 압축하면:

이런 사람에게 맞다

단순히 쓰기만 할 사람

웹/앱 프론트엔드 개발자라면 별다른 고민 없이 설치해 쓰면 된다. 특히 shadcn/ui를 쓰는 React 프로젝트라면 이미 Lucide가 기본값으로 딸려 있을 가능성이 높다.

이런 사람에게 맞다

"코드 생성기 만들기"를 배우고 싶은 사람

하나의 데이터 원본에서 여러 출력 포맷을 만들어내는 코드 생성(code generation) 파이프라인을 실전 규모로 읽어보고 싶은 개발자에게 이 레포는 훌륭한 교재다. tools/build-icons의 파싱 → 템플릿 함수 → 파일 생성 구조는 다른 도메인(다국어 번역 파일, API 클라이언트 자동 생성 등)에도 그대로 응용된다.

이런 사람은 주의

"아이콘 디자인 규칙이 완전 자동으로 검증된다"고 기대하는 사람

새 아이콘을 기여하려는 디자이너라면, CI가 다 걸러줄 거라 기대하지 말고 Lucide Studio로 직접 그리드에 맞추고 docs/contribute/icon-design-guide.md의 14개 조항을 스스로 점검한 뒤 PR을 올리는 편이 리뷰 왕복을 줄인다.