Skip to main content

17장. 커스텀 노드 개발 입문

PART 5 / 17장. 커스텀 노드 개발 입문

커스텀 노드를 만드는 순간, ComfyUI는 플랫폼이 된다

ComfyUI를 한동안 쓰다 보면 비슷한 순간이 반복된다. 누군가가 만든 커스텀 노드를 찾아보지만 딱 맞는 것이 없고, 비슷한 노드 셋을 여러 개 깔았다가 충돌만 늘어난다. 이때부터 시선이 바뀌어야 한다. 이제 당신은 단순한 사용자보다 한 단계 앞으로 나가야 한다. 필요한 기능을 직접 만드는 사람, 즉 생태계의 소비자이자 생산자가 되는 것이다.

프로덕션 관점에서 커스텀 노드는 특히 세 가지 상황에서 빛난다.

  • 워크플로우마다 반복하는 자잘한 전처리나 후처리를 한 노드로 묶고 싶을 때

  • 팀의 이름 규칙, 파일 규칙, 프롬프트 규칙처럼 작업 표준을 강제하고 싶을 때

  • 외부 API, 사내 도구, 데이터베이스, 스프레드시트와 ComfyUI를 연결하고 싶을 때

이 장의 목표는 거창한 플러그인 개발이 아니다. 먼저 노드가 어떻게 생겼는지 이해하고, 30줄 안팎의 작은 노드를 직접 만들고, 그다음 배포와 보안까지 보는 것이다. 여기까지 오면 남이 만든 노드를 설치하는 단계에서 멈추지 않는다. 복잡한 요구가 생겼을 때 스스로 해법을 만들 수 있다.

17.1 커스텀 노드 구조 이해하기

ComfyUI의 커스텀 노드는 본질적으로 파이썬으로 작성한 확장 모듈이다. 기본 설치 방식도 단순하다. 노드 코드를 ComfyUI/custom_nodes 아래에 두고, 필요한 Python 의존성을 설치하면 된다. ComfyUI는 시작할 때 이 디렉터리를 스캔해 노드를 불러오므로, 노드 설치는 사실상 코드 실행 권한을 들여오는 일과 같다.12

가장 먼저 머릿속에 넣어야 할 그림은 이것이다. 커스텀 노드는 대체로 세 층으로 나뉜다.

  • 백엔드 노드: 파이썬 클래스가 실제 연산을 수행한다.

  • 프런트엔드 확장: 필요하면 자바스크립트로 위젯이나 UI 동작을 확장한다.

  • 패키징 정보: requirements.txt, pyproject.toml, README, 예제 워크플로우 같은 배포 정보가 붙는다.

입문 단계에서는 백엔드 노드만 알아도 충분하다. 가장 전통적인 구조는 다음과 같다.

custom_nodes/
  my_production_nodes/
    __init__.py
    project_tag_text.py
    requirements.txt
    README.md

여기서 __init__.py는 입구다. ComfyUI가 이 폴더를 읽을 때 어떤 노드를 외부에 공개할지 알려주는 역할을 한다. 실제 기능은 보통 별도의 .py 파일에 들어간다.

레거시 방식의 노드는 대체로 다섯 가지 요소를 가진다.

INPUT_TYPES는 입력 포트를 정의한다. 문자열, 정수, 이미지, 모델 같은 타입과 기본값, 범위, 위젯 옵션이 여기서 정해진다. RETURN_TYPES는 출력 포트 타입이다. FUNCTION은 실제 실행할 메서드 이름이고, CATEGORY는 노드 메뉴에서 어디에 놓일지를 정한다. 마지막으로 NODE_CLASS_MAPPINGS는 이 클래스들을 ComfyUI에 등록하는 사전이다. 익숙해지면 이것이 결국 함수 시그니처를 UI로 펼쳐 놓은 형태라는 사실이 보인다.

프로덕션에서 더 중요한 관점은 노드를 상태 저장 객체로 보지 않는 것이다. 좋은 노드는 가능하면 입력을 받아 출력을 돌려주는 작은 순수 함수에 가깝다. 이렇게 만들어야 재현성이 높고, 디버깅이 쉽고, 나중에 API나 배치 환경으로 옮기기도 편하다.

2026년 기준으로는 한 가지 흐름을 더 알아야 한다. 커스텀 노드 생태계는 오래된 V1 스타일에서, 공개 API와 버전 고정을 갖춘 V3 스타일로 이동하는 중이다. V3에서는 io.ComfyNode, define_schema(), comfy_entrypoint() 같은 구조를 사용하고, comfy_api.latest 또는 고정 버전 import를 통해 호환성을 관리한다. 요점은 단순하다. 예전에는 내부 구현을 건드리다 깨지는 일이 잦았지만, 이제는 공용 API를 중심으로 더 안정적인 확장이 가능해지고 있다는 뜻이다.3

실전 감각으로 정리하면 이렇다. 지금 당장 배우기에는 V1 구조가 가장 쉽고, 실제 공개 배포를 오래 유지하려면 V3 방향을 염두에 두는 것이 좋다. 입문은 단순하게, 설계는 미래지향적으로 가져가면 된다.

17.2 첫 번째 노드 만들기 — Python으로 30줄

처음부터 이미지 텐서를 만지작거릴 필요는 없다. 첫 노드는 문자열이나 정수처럼 눈에 보이는 타입이 좋다. 여기서는 실무에서 은근히 자주 쓰이는 아주 작은 텍스트 유틸리티 노드를 만들어 보자. 프로젝트명 접두어를 붙이거나, 결과물 이름 규칙을 맞출 때 유용하다.

먼저 폴더를 만든다.

ComfyUI/custom_nodes/my_production_nodes/

그 안에 project_tag_text.py를 만든다.

class ProjectTagText:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            'required': {
                'text': ('STRING', {'multiline': True, 'default': ''}),
                'prefix': ('STRING', {'default': '[CLIENT-A] '}),
                'suffix': ('STRING', {'default': ''}),
                'uppercase': ('BOOLEAN', {'default': False}),
            }
        }

    RETURN_TYPES = ('STRING',)
    RETURN_NAMES = ('text',)
    FUNCTION = 'run'
    CATEGORY = 'production/text'

    def run(self, text, prefix, suffix, uppercase):
        result = f'{prefix}{text}{suffix}'
        if uppercase:
            result = result.upper()
        return (result,)


NODE_CLASS_MAPPINGS = {
    'ProjectTagText': ProjectTagText,
}

NODE_DISPLAY_NAME_MAPPINGS = {
    'ProjectTagText': 'Project Tag Text',
}

이제 같은 폴더에 __init__.py를 만든다.

from .project_tag_text import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS

__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']

이게 끝이다. 정말이다. 처음엔 너무 간단해서 오히려 불안할 수 있는데, 커스텀 노드의 핵심은 원래 이 정도로 단순하다.

코드를 읽는 방법도 같이 익혀 보자. text, prefix, suffix, uppercase는 입력 포트가 된다. run 메서드는 입력을 받아 문자열을 조립한다. RETURN_TYPES가 STRING이므로 출력도 문자열 포트 하나다. CATEGORY를 production/text로 잡았으니 노드 검색 메뉴에서도 그 경로 아래 정리된다.

설치는 세 단계면 충분하다. 파일을 저장하고 ComfyUI를 재시작한 다음, 노드 검색창에서 Project Tag Text를 찾는다. 보이면 성공이다. 안 보이면 대개 둘 중 하나다. __init__.py가 잘못되었거나, 파이썬 문법 오류가 있다. 첫 커스텀 노드에서 가장 흔한 실패 원인은 대단한 알고리즘이 아니라 쉼표 하나 빠진 것이다. 프로그래밍의 세계에 온 것을 환영한다.

여기서 한 걸음만 더 가면, 실무용 작은 노드들을 빠르게 만들 수 있다. 예를 들면 프롬프트 앞에 브랜드 문구를 붙이는 노드, 저장 파일명을 날짜 규칙으로 바꾸는 노드, 특정 숫자를 최소·최대 범위 안으로 고정하는 노드, API 응답에서 필요한 필드만 뽑는 노드가 모두 같은 패턴으로 만들어진다. 핵심은 크고 복잡한 것을 한 번에 만들지 않는 것이다. 먼저 잘게 쪼개고, 노드 하나가 한 가지 일만 하게 하라.

참고로 앞으로 공개 배포를 염두에 둔다면 V3 스타일도 눈여겨볼 만하다. V3에서는 노드 인터페이스를 사전 대신 명시적 스키마로 정의하고, comfy_entrypoint()를 통해 확장을 노출한다. 특히 버전 고정 import가 가능해져서 장기 유지보수성이 좋아진다.3

17.3 노드 배포와 Manager 등록

내 컴퓨터에서 잘 돌아가는 노드와, 남도 쉽게 설치할 수 있는 노드는 다른 문제다. 배포 단계부터는 코딩보다 포장 기술이 더 중요해진다. 최소한 다음 파일들은 챙기는 편이 좋다.

  • README.md: 무엇을 하는 노드인지, 어떻게 쓰는지, 어떤 모델이나 다른 노드가 필요한지 설명한다.

  • requirements.txt: 추가 Python 패키지가 있다면 여기 적는다.

  • pyproject.toml: 레지스트리 배포용 메타데이터와 버전 정보를 담는다.

  • LICENSE: 상업 사용과 재배포 범위를 명확히 한다.

  • 예제 워크플로우: 사용자가 설치 후 바로 검증할 수 있게 해 준다.

2026년의 권장 배포 흐름은 Comfy Registry 중심이다. 먼저 퍼블리셔 계정을 만들고, comfy node init으로 pyproject.toml을 생성한 뒤, PublisherId, 표시 이름, 저장소 URL, 버전 같은 메타데이터를 채운다. 그다음 comfy node publish 또는 GitHub Actions로 배포하면 레지스트리에 올라간다.4

pyproject.toml은 단순한 장식이 아니다. 사용자에게는 설치 정보이고, 도구에게는 배포 계약서다. 이름은 가능하면 짧고 명확하게 짓고, 버전은 의미 있는 변경이 있을 때만 올려라. 프로덕션 팀에서 가장 피곤한 노드는 기능이 강한 노드가 아니라, 버전 정책이 엉망인 노드다.

ComfyUI Manager와의 연결도 이해해 둘 필요가 있다. Manager는 커스텀 노드를 설치할 때 저장소를 가져오고, requirements.txt 의존성을 설치하며, 필요하면 install.py, uninstall.py, disable.py, enable.py 같은 생명주기 스크립트도 호출할 수 있다. NODE_CLASS_MAPPINGS 패턴이 일반적이지 않을 때는 node_list.json으로 노드 목록을 보조할 수도 있다.5

흐름을 아주 단순하게 말하면 이렇다. 사용자는 Manager에서 설치 버튼을 누르고, 배포자는 저장소와 메타데이터를 잘 준비해 둔다. 즉, 좋은 노드는 코드만 좋은 것이 아니라 설치 경험도 좋아야 한다.

한편 실무에서는 아직 두 갈래 길이 공존한다. 최신 흐름은 Registry 배포이고, 레거시 흐름은 Manager 목록 등록용 PR 방식이다. 현재 Manager는 레지스트리와 긴밀하게 연결되어 있고, 메타데이터 표준도 pyproject.toml 중심으로 이동하고 있다. 또한 스냅샷 기능으로 설치 상태를 저장·복원할 수 있어, 새 노드를 실험할 때 매우 유용하다. 중요한 점 하나만 더 기억하자. 이제는 저장소 이름과 실제 설치 디렉터리 이름이 항상 같다고 가정하면 안 된다. 일부 환경에서는 pyproject.toml의 이름이 정규화되어 디렉터리명이 결정될 수 있으므로, 경로 하드코딩 습관은 버리는 편이 안전하다.6

배포용 노드를 만들 때는 다음 원칙이 특히 중요하다. 첫째, 의존성은 최소화하라. 둘째, 외부 패키지 버전은 너무 느슨하게 열어 두지 마라. 셋째, 예제 워크플로우를 반드시 함께 제공하라. 넷째, 실패했을 때 어떤 로그를 보라고 README에 적어 두라. 좋은 노드는 사용자를 똑똑하게 만들고, 나쁜 노드는 이슈 트래커를 길게 만든다.

17.4 안전한 커스텀 노드 고르는 법 — 보안과 의존성 관리

이제 가장 현실적인 이야기를 해 보자. 커스텀 노드는 기능 확장이지만, 동시에 공급망 위험도 늘린다. 설치하는 순간 그 코드는 당신의 ComfyUI 프로세스 안으로 들어온다. 심지어 ComfyUI는 시작 시 custom_nodes 아래 코드를 로드하므로, 악의적인 파일이 들어오면 재시작만으로도 문제가 커질 수 있다.2

그래서 생산자 관점과 사용자 관점 모두에서 기준이 필요하다. Registry 표준은 몇 가지 금지선을 분명하게 제시한다. eval과 exec 사용 금지, 런타임에 subprocess로 pip install을 때리는 방식 금지, 코드 난독화 금지다. 한마디로 정리하면, 리뷰할 수 없고 예측할 수 없는 코드는 배포하지 말라는 뜻이다.7

실제로 노드를 고를 때는 다음 체크리스트를 습관처럼 보는 편이 좋다.

  • 설치 출처가 명확한가. 가능하면 Registry나 Manager에 등록된 배포본을 우선한다.

  • requirements.txt와 install.py에 수상한 다운로드, 원격 실행, 과도한 시스템 접근이 없는가.

  • README에 필요한 모델, 의존성, 지원 버전, 예제 워크플로우가 정리되어 있는가.

  • 최근 커밋, 이슈 응답, 릴리스 태그가 있는가. 오래된 노드가 무조건 나쁜 것은 아니지만, 깨졌을 때 혼자 울 가능성은 높다.

  • 설치 전에 스냅샷이나 별도 테스트 환경을 준비했는가.

  • 외부에 공개된 ComfyUI 서버라면 인증과 네트워크 제한을 갖췄는가.

특히 마지막 항목은 과소평가되기 쉽다. ComfyUI 자체에는 기본 인증과 권한 관리가 내장되어 있지 않다는 점이 오래전부터 지적되어 왔다. 따라서 인터넷에 직접 노출하는 구성은 피하고, 최소한 리버스 프록시와 인증 계층을 둬야 한다. 필요하면 로그인, IP 필터링, 사용자별 디렉터리 분리를 제공하는 보안 확장을 검토할 수도 있다. 다만 이런 확장도 만능 방패는 아니다. 보안은 플러그인 하나로 끝나는 기능이 아니라, 배포 구조 전체의 책임이다.28

의존성 관리도 보안과 직결된다. 두 노드 팩이 서로 다른 OpenCV나 Pillow 버전을 요구하면 기능 충돌이 날 수 있고, 심하면 환경 전체가 망가진다. 그래서 프로덕션 환경에서는 새 노드를 바로 운영 인스턴스에 넣지 말고, 테스트 인스턴스에서 먼저 검증하는 편이 좋다. V3가 지향하는 프로세스 격리와 공개 API 안정성은 바로 이런 문제를 줄이기 위한 방향이다.3

결국 안전한 커스텀 노드 문화는 기술보다 태도에 가깝다. 개발자는 과한 마법을 넣지 말고, 사용자는 설치 버튼을 신용카드 결제 버튼만큼 신중하게 눌러야 한다. 노드는 작을수록 이해하기 쉽고, 이해하기 쉬울수록 운영하기 쉽다.

제작자의 시선으로 ComfyUI를 다시 보기

커스텀 노드 개발 입문은 파이썬을 깊게 배우는 장이 아니다. 오히려 ComfyUI를 다른 눈으로 보는 장이다. 이제 캔버스 위의 노드는 누가 만든 검은 상자가 아니다. 입력과 출력, 책임과 계약, 배포와 보안이 있는 작은 소프트웨어다.

이 시선을 얻고 나면 실무가 달라진다. 원하는 기능이 없을 때 기다리기보다 만들 수 있고, 남의 노드를 설치할 때도 구조를 읽을 수 있고, 팀의 파이프라인을 더 안전하고 더 재현 가능하게 다듬을 수 있다. 그리고 바로 그 지점에서 ComfyUI는 이미지 생성 도구를 넘어, 당신이 설계하는 콘텐츠 운영체제가 된다.

참고

1Install Custom Node 공식 문서

2Snyk의 ComfyUI 커스텀 노드 보안 분석

3ComfyUI V3 custom node schema 해설

4Comfy Registry 배포 가이드

5Publishing to the Manager 공식 문서

6ComfyUI-Manager README

7Comfy Registry Standards

8ComfyUI Sentinel 저장소

책 목록

프로덕션 ComfyUI: 이미지에서 영상까지, 노드로 완성하는 AI 콘텐츠 파이프라인

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기