> ## Documentation Index
> Fetch the complete documentation index at: https://docs.comfy.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Reemplazo de nodos

> Registra reemplazos de nodos para que los usuarios migren de los nodos obsoletos

La API de reemplazo de nodos permite a los desarrolladores de nodos personalizados definir rutas de migración desde nodos obsoletos hasta sus equivalentes más recientes. Cuando actualizas o renombras nodos, los usuarios pueden actualizar automáticamente sus flujos de trabajo.

## Cuándo usar

* **Cambiar nombres de clase de nodo**: Cambiaste el nombre de clase de un nodo (usa `DISPLAY_NAME` para cambios de nombre para mostrar en su lugar)
* **Fusionar nodos**: Varios nodos consolidados en uno (p. ej., `Load3DAnimation` fusionado en `Load3D`)
* **Refactorizar entradas**: Los nombres o tipos de las entradas cambiaron entre versiones
* **Corregir errores tipográficos**: Corregir nombres de nodos sin romper los flujos de trabajo existentes

## Dónde registrar los reemplazos

Registra los reemplazos durante el gancho de ciclo de vida `on_load` de tu extensión. Crea un archivo dedicado (p. ej., `node_replacements.py`) en el paquete de tu nodo personalizado:

```
my_custom_nodes/
├── __init__.py
├── nodes.py
└── node_replacements.py   # Register replacements here
```

## Ejemplo completo

Aquí tienes un ejemplo completo de cómo estructurar los reemplazos de nodos en un paquete de nodo personalizado:

```python theme={null}
# node_replacements.py
from comfy_api.latest import ComfyExtension, io, ComfyAPI

api = ComfyAPI()


async def register_my_replacements():
    """Register all node replacements for this package."""
    
    # Simple rename - no input changes needed
    await api.node_replacement.register(io.NodeReplace(
        new_node_id="MyNewNode",
        old_node_id="MyOldNode",
    ))
    
    # Complex replacement with input mapping
    await api.node_replacement.register(io.NodeReplace(
        new_node_id="MyImprovedSampler",
        old_node_id="MyOldSampler",
        old_widget_ids=["steps", "cfg"],
        input_mapping=[
            {"new_id": "model", "old_id": "model"},
            {"new_id": "num_steps", "old_id": "steps"},
            {"new_id": "guidance", "old_id": "cfg"},
            {"new_id": "scheduler", "set_value": "normal"},  # New input with default
        ],
        output_mapping=[
            {"new_idx": 0, "old_idx": 0},
        ],
    ))


class MyExtension(ComfyExtension):
    async def on_load(self) -> None:
        await register_my_replacements()

    async def get_node_list(self) -> list[type[io.ComfyNode]]:
        return []  # No nodes defined here, just replacements


async def comfy_entrypoint() -> MyExtension:
    return MyExtension()
```

## Ejemplos del núcleo

El núcleo de ComfyUI usa reemplazos de nodos para las migraciones de nodos integrados. Aquí tienes ejemplos reales de [`comfy_extras/nodes_replacements.py`](https://github.com/Comfy-Org/ComfyUI/blob/master/comfy_extras/nodes_replacements.py):

### Fusión simple de nodos

Cuando `Load3DAnimation` se fusionó en `Load3D`:

```python theme={null}
await api.node_replacement.register(io.NodeReplace(
    new_node_id="Load3D",
    old_node_id="Load3DAnimation",
))
```

### Corrección de errata

Corrección de una errata en `SDV_img2vid_Conditioning` → `SVD_img2vid_Conditioning`:

```python theme={null}
await api.node_replacement.register(io.NodeReplace(
    new_node_id="SVD_img2vid_Conditioning",
    old_node_id="SDV_img2vid_Conditioning",
))
```

### Renombrar entradas con valores predeterminados

Sustituir `ImageScaleBy` por `ResizeImageMaskNode`:

```python theme={null}
await api.node_replacement.register(io.NodeReplace(
    new_node_id="ResizeImageMaskNode",
    old_node_id="ImageScaleBy",
    old_widget_ids=["upscale_method", "scale_by"],
    input_mapping=[
        {"new_id": "input", "old_id": "image"},
        {"new_id": "resize_type", "set_value": "scale by multiplier"},
        {"new_id": "resize_type.multiplier", "old_id": "scale_by"},
        {"new_id": "scale_method", "old_id": "upscale_method"},
    ],
))
```

### Mapeo de entradas Autogrow

Para los nodos que usan Autogrow (entradas dinámicas), usa la notación con puntos:

```python theme={null}
await api.node_replacement.register(io.NodeReplace(
    new_node_id="BatchImagesNode",
    old_node_id="ImageBatch",
    input_mapping=[
        {"new_id": "images.image0", "old_id": "image1"},
        {"new_id": "images.image1", "old_id": "image2"},
    ],
))
```

## Parámetros de NodeReplace

| Parámetro | Tipo | Descripción |
| - | - | - |
| `new_node_id` | str | Nombre de clase del nodo de reemplazo |
| `old_node_id` | str | Nombre de clase del nodo obsoleto |
| `old_widget_ids` | list\[str] \| None | Lista ordenada que vincula los IDs de widget con sus índices relativos |
| `input_mapping` | list \| None | Cómo asignar las entradas del nodo antiguo al nuevo |
| `output_mapping` | list \| None | Cómo asignar las salidas del nodo antiguo al nuevo |

## Mapeo de entradas

Cada entrada del mapeo define cómo se transfiere una entrada del nodo antiguo al nuevo.

**Mapear desde una entrada antigua:**

```python theme={null}
{"new_id": "model", "old_id": "model"}
```

**Establecer un valor fijo:**

```python theme={null}
{"new_id": "scheduler", "set_value": "normal"}
```

**Mapear entradas dinámicas o autogrow (usa la notación con puntos):**

```python theme={null}
{"new_id": "images.image0", "old_id": "image1"}
```

## Mapeo de salidas

Los mapeos de salidas usan referencias basadas en índices:

```python theme={null}
{"new_idx": 0, "old_idx": 0}  # Map first output
{"new_idx": 1, "old_idx": 0}  # Old output 0 -> new output 1
```

## Vinculación de IDs de widget

El campo `old_widget_ids` asigna los IDs de widget a sus índices posicionales. Esto es necesario porque el JSON del flujo de trabajo guarda los valores de los widgets por posición, no por ID.

```python theme={null}
old_widget_ids=["steps", "cfg", "sampler"]
# Widget at index 0 = "steps"
# Widget at index 1 = "cfg"
# Widget at index 2 = "sampler"
```

## API REST

Recupera todos los reemplazos registrados:

```
GET /api/node_replacements
```

**Respuesta:**

```json theme={null}
{
  "OldSamplerNode": [
    {
      "new_node_id": "NewSamplerNode",
      "old_node_id": "OldSamplerNode",
      "old_widget_ids": ["num_steps", "cfg_scale", "sampler_name"],
      "input_mapping": [
        {"new_id": "model", "old_id": "model"},
        {"new_id": "steps", "old_id": "num_steps"},
        {"new_id": "scheduler", "set_value": "normal"}
      ],
      "output_mapping": [
        {"new_idx": 0, "old_idx": 0}
      ]
    }
  ]
}
```

## Comportamiento del frontend

Cuando un flujo de trabajo contiene un nodo obsoleto, el frontend:

1. Obtiene los reemplazos desde `GET /api/node_replacements`
2. Detecta los nodos que coinciden con `old_node_id`
3. Pide al usuario que los actualice
4. Aplica las asignaciones de entrada/salida automáticamente
5. Conserva las conexiones y los valores de los widgets

Consulta la implementación del frontend:

* [PR #8364 de lógica de negocio](https://github.com/Comfy-Org/ComfyUI_frontend/pull/8364)
* [PR #8483 de lógica adicional](https://github.com/Comfy-Org/ComfyUI_frontend/pull/8483)
* [PR #8604 de vistas de UI](https://github.com/Comfy-Org/ComfyUI_frontend/pull/8604)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.