Subidas e integración frontend

# Cómo aceptar subidas grandes pese a una conexión interrumpida

Acepta subidas de varios gigabytes mediante el protocolo tus, reanúdalas tras perder la conexión y mantén viva la Assembly hasta terminarlas.

Publicado el 13 de agosto de 2026

## Conclusiones clave

* Los archivos incluidos en la solicitud multipart de creación de la Assembly no pueden reanudarse, por lo que cualquier interrupción hace fallar toda la Assembly.
* Subir mediante el protocolo tus permite que un cliente continúe desde el desplazamiento de bytes que el servidor ya conserva, en lugar de comenzar de nuevo.
* Primero crea la Assembly con num\_expected\_upload\_files y luego sube los archivos a la tus\_url que devuelve.

Una subida grande no es una solicitud que falla ocasionalmente. Es una transferencia que se interrumpirá, y la única decisión real es si una interrupción le cuesta al usuario los bytes restantes o todos ellos. Todo lo demás en el diseño se deriva de esa elección.

## En esta guía

1. [Distingue las dos rutas de subida: solo una se reanuda](#resumable-uploads-for-large-files-section-1)
2. [Declara cuántos archivos se recibirán](#resumable-uploads-for-large-files-section-2)
3. [Reanuda desde un desplazamiento, no mediante un reintento](#resumable-uploads-for-large-files-section-3)
4. [Reanuda la transferencia, pero ten en cuenta que la Assembly aún vence](#resumable-uploads-for-large-files-section-4)
5. [Adjunta los metadatos que necesita cada archivo](#resumable-uploads-for-large-files-section-5)
6. [Firma la solicitud cuando el navegador sea el cliente](#resumable-uploads-for-large-files-section-6)

## Lo más importante

* Las subidas que exceden la cantidad declarada se descartan silenciosamente, por lo que un desfase de uno en esa cifra provoca la pérdida de archivos sin generar un error.
* Los archivos pueden tener hasta 200 GB, pero la Assembly vence de todos modos ocho horas después de su creación.

## Distingue las dos rutas de subida: solo una se reanuda

Transloadit acepta archivos de dos maneras, y la diferencia entre ellas solo se manifiesta con una mala conexión. Los archivos pueden adjuntarse a la solicitud POST `multipart/form-data` que crea la Assembly, una opción sencilla y adecuada para una foto de perfil. Cualquier interrupción de esa solicitud hace fallar tanto la subida como la Assembly, y el cliente no tiene forma de continuar: solo puede enviarlo todo de nuevo.

La otra opción usa [el protocolo tus⁠](https://tus.io/), un protocolo abierto para subidas reanudables mediante HTTP, con implementaciones de cliente en la mayoría de los lenguajes. Transloadit ejecuta un servidor tus, y un cliente compatible con el protocolo puede pausar la transferencia, perder la conexión y retomarla desde el último byte confirmado por el servidor. Para cualquier archivo de cientos de megabytes, esa es la diferencia entre una subida que finalmente termina y otra que nunca lo hace.

### Multipart

Una solicitud que transporta los archivos. Una interrupción hace fallar tanto la subida como la Assembly.

### tus

Una transferencia independiente por archivo que puede continuar desde el último byte confirmado.

### Ya resuelto para ti

Uppy y los SDK del back end usan el protocolo tus internamente, por lo que la mayoría de las integraciones obtiene esta capacidad sin trabajo adicional.

## Declara cuántos archivos se recibirán

Una subida reanudable invierte el orden habitual: la Assembly se crea antes de que se envíe cualquier byte. La solicitud de creación incluye `params` como de costumbre, además de un campo `num_expected_upload_files` que indica cuántos archivos se enviarán después, y no contiene datos de ningún archivo. La respuesta es un Assembly Status convencional con dos adiciones relevantes: `tus_url`, que indica adónde se envían las subidas, y el trío `expected_tus_uploads`, `started_tus_uploads` y `finished_tus_uploads`, que permite seguirlas.

Esa cantidad declarada se aplica con más rigor de lo que parece al principio. La Assembly permanece en `ASSEMBLY_UPLOADING` hasta que hayan terminado todas las subidas esperadas, incluso cuando los archivos que llegaron antes ya se hayan procesado. Las subidas que exceden la cantidad declarada se descartan sin generar un error, lo que convierte una cifra incorrecta en uno de los fallos más difíciles de detectar: la Assembly finaliza correctamente y simplemente falta un archivo en los resultados.

Crear la Assembly antes de enviar cualquier byte

```
POST /assemblies HTTP/1.1
Host: api2.transloadit.com
Content-Type: multipart/form-data; boundary=---xyz

-----xyz
Content-Disposition: form-data; name="params"

{"auth":{"key":"YOUR_KEY"},
 "template_id":"YOUR_TEMPLATE_ID"}
-----xyz
Content-Disposition: form-data;
  name="num_expected_upload_files"

2
-----xyz--
```

### num\_expected\_upload\_files

Configúralo con la cantidad exacta de archivos que enviará el cliente y cuenta los archivos antes de crear la Assembly.

### tus\_url

El endpoint de subida de esta Assembly, devuelto en el Assembly Status en lugar de estar definido directamente en el código.

### Los archivos adicionales desaparecen

Todo lo que exceda la cantidad declarada se descarta silenciosamente, por lo que conviene validar esa cifra.

## Reanuda desde un desplazamiento, no mediante un reintento

Cada subida comienza con una solicitud POST a `tus_url` que crea un recurso en lugar de enviar datos. La solicitud incluye tres metadatos, `assembly_url`, `filename` y `fieldname`, y el servidor responde con una URL de subida en el encabezado `Location`. Después, los bytes se transfieren a esa URL mediante una o más solicitudes PATCH y, cuando llega la última, el archivo se incorpora a la Assembly sin ninguna llamada adicional.

La recuperación utiliza la misma URL. Una solicitud HEAD devuelve un encabezado `Upload-Offset` con la cantidad de bytes que el servidor realmente tiene, y el cliente reanuda la transferencia mediante una solicitud PATCH que comienza exactamente en ese desplazamiento. Por eso, reintentar y reanudar no son la misma operación: un reintento vuelve a enviar el archivo desde cero, mientras que una reanudación consulta al servidor qué parte ya tiene y envía solo la diferencia.

Consultar el desplazamiento y enviar solo el resto

```
HEAD /resumable/files/136058f2ef4d HTTP/1.1
Host: api2-freja.transloadit.com
Tus-Resumable: 1.0.0

HTTP/1.1 204 No Content
Upload-Offset: 3000
Upload-Length: 10000

PATCH /resumable/files/136058f2ef4d HTTP/1.1
Host: api2-freja.transloadit.com
Tus-Resumable: 1.0.0
Upload-Offset: 3000
Content-Length: 7000
Content-Type: application/offset+octet-stream
```

### Crear y luego transferir

La primera solicitud POST establece la URL de subida; las solicitudes PATCH transfieren el contenido real.

### Upload-Offset

El servidor indica cuánto recibió, por lo que el cliente nunca tiene que adivinar desde dónde continuar.

### Conservar la URL de subida

Para reanudar después de volver a cargar una página se necesita esa URL, así que guárdala de forma persistente en lugar de conservarla en memoria.

## Reanuda la transferencia, pero ten en cuenta que la Assembly aún vence

La capacidad de reanudación suele interpretarse como un periodo de gracia ilimitado, pero no lo es. La Assembly se creó al principio y su reloj ya está en marcha: la subida está limitada a ocho horas; el procesamiento, a ocho horas adicionales; y ambos en conjunto, a dieciséis horas desde la creación. Una Assembly que supera esos límites devuelve `ASSEMBLY_EXPIRED`, y la subida parcial asociada deja de ser útil.

Esto importa sobre todo para las cargas de trabajo que de entrada necesitan capacidad de reanudación. Un usuario que pausa durante la noche una subida de gran tamaño volverá a una Assembly que ya no existe, así que el cliente debe detectar ese caso y crear una nueva en lugar de reintentar con una URL inactiva. Tratar el vencimiento como un resultado esperado, en vez de como un error que debe registrarse, mantiene clara la lógica de esa ruta de recuperación.

### Ocho horas para subir

Se mide desde la creación de la Assembly, no desde la última vez que avanzó la transferencia.

### Límite de dieciséis horas

La subida y el procesamiento combinados no pueden superar las dieciséis horas desde la creación.

### Planificar un reinicio

Detecta una Assembly vencida y crea una nueva en lugar de reintentar con la URL de la subida anterior.

## Adjunta los metadatos que necesita cada archivo

Además de los tres valores obligatorios, cualquier metadato adicional enviado con una subida queda disponible como una Assembly Variable en `file.user_meta`; por eso, una clave enviada como `owner` se lee como `${file.user_meta.owner}`. Conviene asimilar pronto esta diferencia, porque `fields` se comparte entre todos los archivos de la Assembly, mientras que los metadatos del usuario pertenecen a un solo archivo. Si cada archivo de un lote necesita su propia ruta de destino, propietario o categoría, debes usar estos últimos. Si intentas expresarlo mediante campos compartidos, terminarás con un Template que no puede distinguir los archivos.

Para crear ramificaciones según el contenido y no según lo que declaró el cliente, utiliza preferentemente `${file.mime}` y busca coincidencias con familias como `image/*` o `video/*`. Un nombre de archivo o una categoría proporcionados por el cliente son solo indicios; tratarlos como hechos puede hacer que un ejecutable termine en una ruta que daba por supuesto que recibiría imágenes. La categoría general `${file.type}` también existe, pero la coincidencia por MIME es la más exacta de las dos.

### Tres valores obligatorios

Cada subida necesita assembly\_url, filename y fieldname en sus metadatos del protocolo tus.

### Por archivo o por Assembly

Los metadatos del usuario pertenecen a un solo archivo; los campos se comparten entre todos los archivos de la misma ejecución.

### Crear ramificaciones según MIME

Busca coincidencias con ${file.mime} en lugar de confiar en una extensión o una categoría proporcionada por el cliente.

## Firma la solicitud cuando el navegador sea el cliente

Una subida que comienza en un navegador implica que las Assembly Instructions se envían desde un entorno que no controlas. Signature Authentication cierra esa brecha: tu back end firma los params con el Auth Secret, añade una marca de tiempo `auth.expires` para un momento próximo y entrega el resultado al front end. Activar este requisito en la Configuración del Workspace hace que la API rechace cualquier solicitud sin firma para la cuenta.

La ventaja es que tu servidor decide qué está dispuesto a firmar. Puede rechazar a usuarios anónimos, limitar el Template que una solicitud puede invocar o restringir los parámetros antes de firmarlos, todo mediante la lógica habitual de la aplicación. El Auth Secret nunca sale del back end, y una firma interceptada solo es válida hasta el vencimiento con el que se emitió.

Obtener la firma desde tu propio back end

```
const uppy = new Uppy().use(Transloadit, {
  waitForEncoding: true,
  assemblyOptions: async () => {
    // Your back end signs with the Auth Secret
    const res = await fetch('/api/tl-signature')
    const { params, signature } = await res.json()
    return { params, signature }
  },
})
```

### Firmar en el servidor

El Auth Secret permanece en el back end y nunca llega a un paquete del navegador.

### auth.expires

Una marca de tiempo próxima que limita durante cuánto tiempo puede utilizarse una firma emitida.

### Exigir la firma

La Configuración del Workspace puede rechazar categóricamente, sin excepciones, todas las solicitudes sin firma para la cuenta.

## Detalles técnicos que conviene conocer

* La Assembly se crea mediante una solicitud POST multipart que incluye params y num\_expected\_upload\_files, pero no contenido de archivos, y la respuesta incluye tus\_url, expected\_tus\_uploads, started\_tus\_uploads y finished\_tus\_uploads.
* Una Assembly permanece en el estado ASSEMBLY\_UPLOADING hasta que finalizan todas las subidas declaradas mediante el protocolo tus, incluso cuando algunos de los archivos que ya recibió se hayan procesado.
* Cada subida mediante el protocolo tus comienza con una solicitud POST a tus\_url que incluye assembly\_url, filename y fieldname como metadatos, y el servidor responde con la URL de subida en el encabezado Location.
* La reanudación consiste en una solicitud HEAD a esa URL de subida, que informa la cantidad de bytes recibidos en el encabezado Upload-Offset, seguida de una solicitud PATCH que envía el resto exactamente desde ese desplazamiento.
* Los metadatos adicionales enviados con una subida se convierten en una Assembly Variable en file.user\_meta, que corresponde a cada archivo, a diferencia de fields, que se comparte entre todos los archivos de la misma Assembly.
* La subida está limitada a ocho horas y el procesamiento a otras ocho, con un máximo de dieciséis horas desde la creación; después, la Assembly devuelve ASSEMBLY\_EXPIRED.

## Un enfoque práctico

1. 1\
   Crea la Assembly con num\_expected\_upload\_files configurado con la cantidad exacta de archivos que enviará el cliente.
2. 2\
   Sube cada archivo a la tus\_url del Assembly Status con un cliente tus, en lugar de usar una solicitud POST convencional.
3. 3\
   Guarda de forma persistente la URL de subida en el cliente para poder reanudarla después de recargar la página o de un fallo, en lugar de reiniciarla.
4. 4\
   Firma la solicitud de creación de la Assembly en tu back end siempre que el navegador sea el cliente.

Un flujo de trabajo multimedia de cuatro etapas

## Cuándo resulta útil Transloadit

Usa Uppy con el plugin de Transloadit en el navegador, o cualquier cliente tus en otros entornos, y deja que /upload/handle reciba los archivos. Primero crea la Assembly con num\_expected\_upload\_files y luego envía cada archivo a la tus\_url devuelta en el Assembly Status.

## Límite de la arquitectura

La capacidad de reanudación recupera una transferencia interrumpida, no una olvidada. Las subidas deben finalizar dentro de las ocho horas posteriores a la creación de la Assembly, y el procesamiento dispone de otras ocho horas, con un límite total de dieciséis horas desde la creación. Después, la Assembly devuelve ASSEMBLY\_EXPIRED y los bytes ya recibidos dejan de ser utilizables.

## Preguntas frecuentes

### ¿Tengo que implementar el protocolo tus por mi cuenta?

Por lo general, no. Uppy y los SDK de back end usan el protocolo tus de forma predeterminada, por lo que una integración normal ya obtiene subidas reanudables. Implementar el protocolo directamente sirve para crear un SDK o usar un lenguaje para el que no existe un SDK de Transloadit.

### ¿Por qué algunos de mis archivos nunca aparecieron en los resultados?

La causa probable es que el valor de `num_expected_upload_files` sea menor que la cantidad de archivos realmente enviados. Las subidas que exceden la cantidad declarada se descartan silenciosamente, por lo que la Assembly finaliza correctamente, pero faltan archivos. Cuenta los archivos antes de crear la Assembly.

### ¿Qué ocurre si el usuario cierra la pestaña durante una subida?

La transferencia puede reanudarse siempre que el cliente haya conservado la URL de subida y la Assembly no haya vencido. Guarda esa URL fuera de la memoria de la página y, cuando regreses, envía una solicitud HEAD para conocer el desplazamiento y continuar desde allí.

### ¿Qué tamaño máximo puede tener un archivo que suba?

Se admiten archivos de hasta 200 GB y pueden acordarse límites superiores. En la práctica, la restricción suele ser el tiempo, no el tamaño: la subida dispone de ocho horas desde la creación de la Assembly, y una conexión lenta puede agotarlas antes de que termine un archivo muy grande.

### ¿La información de cada archivo debe ir en los campos o en los metadatos?

Usa los metadatos de subida del protocolo tus cuando el valor pertenezca a un solo archivo, ya que llega como una Assembly Variable en `file.user_meta`. Usa `fields` únicamente para valores compartidos por todos los archivos de la Assembly, como un identificador de cliente que se aplica a todo el lote.

## Crea el flujo de trabajo

Pasa del concepto a una Assembly probada con documentación de Robots y demos funcionales.

### Robots relevantes

* [/upload/handle](/es/docs/robots/upload-handle.md)
* [Lee la documentación de la API](/es/docs.md)
* [Explora demos funcionales EN (English)](/demos.md)
* [Crea un Workspace gratuito](/c/signup/)

Subidas e integración frontend

## Continúa con guías relacionadas

* [Cómo servir imágenes responsivas desde una sola URL](/es/guides/serve-responsive-images-from-one-url.md)\
  Genera cada tamaño de imagen desde una URL canónica, almacena los resultados en caché perimetral y mantén estable el costo de codificación al crecer el tráfico.
* [Automatización de medios: de la subida a resultados confiables](/es/guides/media-automation.md)\
  Automatiza la recepción, transformación, validación y exportación repetibles de medios, a la vez que preservas la observabilidad y el control.
* [Guía de API de subida de archivos: arquitectura, seguridad y selección de proveedores](/es/guides/file-upload-api-guide.md)\
  Elige e implementa una API de subida comparando arquitectura, reanudación, transferencia directa a la nube, seguridad, límites de almacenamiento y proveedores.
* [Subidas seguras de archivos en Next.js con Uppy y Templates firmados de Transloadit](/es/guides/secure-file-uploads-nextjs-uppy.md)\
  Crea una subida segura en Next.js App Router con Uppy: firma en servidor, Template bloqueado, validación autoritativa, transferencia reanudable y fin asíncrono.
* [Mejores bibliotecas JavaScript para subir archivos: Uppy vs FilePond vs Dropzone](/es/guides/best-javascript-file-upload-libraries.md)\
  Compara Uppy, FilePond y Dropzone según el protocolo de transferencia, el modelo de interfaz, la recuperación, la integración y el mantenimiento a largo plazo.
* [Subidas de archivos con React y Uppy: reanudación, vistas previas, validación y procesamiento](/es/guides/react-file-uploads-with-uppy.md)\
  Crea un componente de subida en React con Uppy: vistas previas, validación, progreso accesible, cancelación, reanudación y procesamiento con Transloadit.
