TL;DR, Respuesta Rápida
8 min de lecturaBluesky limita la imagen de un post a 2,000,000 bytes, una cifra escrita como maxSize en el lexicon app.bsky.embed.images, el esquema del protocolo. Son dos millones de bytes, no 2 MiB, así que una imagen que tu gestor de archivos llama 1.95 MB ya se pasa. Avatares, banners y miniaturas de tarjetas de enlace se quedan en la mitad, 1,000,000 bytes. La app de Bluesky nunca envía tu archivo original: recodifica cada imagen de post a JPEG con 4,000 píxeles como máximo y busca una calidad que quepa bajo el tope.
¿Cuál es el límite de tamaño de imagen de Bluesky?
Cada imagen adjunta a un post de Bluesky está topada en 2,000,000 bytes, así que el límite de tamaño de imagen de Bluesky son dos millones de bytes y no los 2 MiB que la mayoría de gestores de archivos quiere decir cuando escribe "2 MB". La cifra no está enterrada en un artículo de ayuda. Está en el esquema del protocolo, en app.bsky.embed.images, como un campo llamado maxSize en el blob de la imagen:
"image": {
"type": "blob",
"description": "The raw image file. May be up to 2 MB, formerly limited to 1 MB.",
"accept": ["image/*"],
"maxSize": 2000000
}Dos millones de bytes son 1.907 MiB. Un JPEG exportado que el Finder de macOS reporta como "1.9 MB" pesa unos 1,992,294 bytes y pasa por los pelos; uno que reporta como "2 MB" pesa 2,097,152 bytes y no pasa. En esa brecha de 97,152 bytes vive casi toda la confusión sobre este límite.
La propia redacción del lexicon conserva la historia. Dice que el blob "May be up to 2 MB, formerly limited to 1 MB", y por eso tantas guías de tamaños de terceros siguen publicando 1 MB. Tenían razón hace dos años y nadie volvió a editarlas.
¿Qué subida de Bluesky recibe qué límite?
Bluesky no tiene un único límite de imagen. Tiene seis topes de blob declarados en seis lexicons, y se contradicen entre sí a propósito.
| Lexicon | Qué contiene | maxSize | accept |
|---|---|---|---|
app.bsky.embed.images | Imágenes de post, hasta 4 | 2000000 | image/* |
app.bsky.embed.gallery | Elementos de galería | 2000000 | image/* |
app.bsky.embed.external | Miniatura de tarjeta de enlace | 1000000 | image/* |
app.bsky.actor.profile | Avatar | 1000000 | image/png, image/jpeg |
app.bsky.actor.profile | Banner | 1000000 | image/png, image/jpeg |
app.bsky.embed.video | Archivo de vídeo | 300000000 | video/mp4 |
Dos cosas de esa tabla pillan a la gente. Los avatares y banners están topados en la mitad de una imagen de post, y rechazan todo lo que no sea PNG o JPEG, así que un avatar WebP que sube sin problema como imagen de post queda rechazado en tu perfil. Y el blob de vídeo llega a 300,000,000 bytes, con su propia descripción anotando que antes estaba "formerly limited to 100mb", el mismo patrón que el tope de imagen.
El lexicon más nuevo, app.bsky.embed.gallery, permite un maxLength de 20 elementos, pero su propio comentario de esquema pide a los clientes que se contengan: "The schema-level maxLength of 20 is a future-proof ceiling. Clients should currently enforce a soft limit of 10 items in authoring UIs." El embed más antiguo, app.bsky.embed.images, se queda en 4.

¿Qué le hace la app de Bluesky a tu imagen antes de subirla?
El cliente oficial nunca envía tu archivo original. Antes de llamar a uploadBlob, el compositor ejecuta compressImage contra una configuración en src/lib/constants.ts:
export const IMAGE_SIZE_CONFIG_POSTS = {
maxDimension: 4000,
maxSize: 2000000,
};Esa función no comprueba si tu archivo ya es lo bastante pequeño. Recodifica sin condiciones, siempre a JPEG, y hace una búsqueda binaria de un nivel de calidad que aterrice por debajo de 2,000,000 bytes. Empieza en calidad 51, sube si el resultado cabe y baja si no cabe, y se detiene cuando la ventana de búsqueda se cierra.
Cuando una imagen se resiste a la compresión, el código se niega a seguir bajando la calidad. El comentario del código fuente deletrea la regla: "binary search will check 51, 26, 13(rounded). We don't want to go below 25, so if we've halved to 13, reset the loop and reduce the image dimensions instead." Cada reinicio multiplica la dimensión de trabajo por 0.8, lo que lleva 4000 a 3200, luego 2560, luego 2048 y luego unos 1638 píxeles. Cuatro reinicios son el techo, y pasado eso la subida falla con Unable to compress image.
De que toda imagen de post se recodifique a JPEG se siguen tres consecuencias. La transparencia desaparece, porque JPEG no tiene canal alfa, así que un logo PNG sobre fondo transparente llega con un fondo sólido. El texto nítido y el color plano recogen artefactos de anillo que ese mismo archivo no mostraría en una plataforma que deja pasar el PNG. Y tus cuidados ajustes de exportación se tiran, porque el cliente elige su propio número de calidad al margen de lo que tú elegiste. Esa misma recodificación también rellena el campo aspectRatio a partir de la salida comprimida y no de tu original, y ese campo son dos enteros con un mínimo de 1, no un float.
¿Por qué una imagen demasiado grande sube igual a veces?
Porque la subida del blob y la escritura del registro son dos peticiones distintas con dos límites distintos, y solo la segunda lee el lexicon.
El endpoint com.atproto.repo.uploadBlob aplica el tope propio del servidor, que en el PDS de referencia vale por defecto 5 * 1024 * 1024, o sea 5,242,880 bytes, configurable con la variable de entorno PDS_BLOB_UPLOAD_LIMIT. Si lo superas, el stream aborta con Max size of 5242880 bytes exceeded. Si te quedas por debajo, el blob se acepta incluso con 4 MB, muy por encima de los 2,000,000 del lexicon.
El lexicon dice dónde ocurre la comprobación de verdad. Su descripción reza: "The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created." Así que una imagen de 4 MB sube con éxito, se queda en almacenamiento temporal, falla la validación cuando intentas adjuntarla a un post y se recoge como basura minutos después. Quien publica con un cliente propio en lugar de la app oficial choca con este orden y lee la subida correcta como luz verde.
Ese mismo endpoint carga con un límite de 1,000 puntos al día, lo que pone un techo duro a cuántas imágenes puede empujar una cuenta en 24 horas. Es uno de varios topes que conviene leer junto a los límites de tasa que el AT Protocol aplica a las escrituras si publicas con calendario.
AdaptlyPost
Prueba gratis de 7 días
Analíticas multiplataforma
Bandeja Social
Asistente con IA

¿Qué dimensiones deberías exportar para Bluesky?
Nada en el lexicon restringe las dimensiones en píxeles. No hay ancho mínimo, ni alto máximo, ni relación de aspecto obligatoria en ninguna parte de app.bsky.embed.images. La única cifra de dimensión que existe es el maxDimension: 4000 del propio cliente, y eso es un disparador de redimensión, no un rechazo.
El consejo práctico que sale de ahí es corto. Exporta a 2,000 píxeles en el lado largo o menos, para que el cliente no tenga motivo de redimensionar ni de bajar la calidad a lo bruto. Usa JPEG tú mismo, ya que la app va a convertir a JPEG de todas formas y tu codificador está mejor afinado que una búsqueda binaria de calidad. Mantén el archivo por debajo de 1.8 MB para dejar margen a la recodificación. Si necesitas transparencia o texto nítido, aplana la imagen sobre el color de fondo que quieras antes de subirla, porque la alternativa es dejar que el codificador JPEG elija por ti.
El texto alternativo no tiene tope declarado en el lexicon. La app oficial aplica su propio MAX_ALT_TEXT = 2000, que es una regla de cliente y no del protocolo, así que otros clientes fijan la suya. Eso refleja cómo Bluesky maneja enlaces y menciones, donde los offsets de bytes en los facets de un post son asunto del protocolo y el renderizado es asunto del cliente.
Si comparas especificaciones entre redes antes de montar un preset de exportación, la aritmética de las dimensiones de imagen de Instagram funciona distinto, porque Meta redimensiona en el servidor en lugar de hacer que el cliente lo haga. Y si preparas imágenes con antelación, el paso de compresión forma parte de programar posts en Bluesky, lo ejecutes tú o lo ejecute un cliente.
Preguntas frecuentes
¿El límite de imagen de Bluesky es 1 MB o 2 MB?
Son 2,000,000 bytes. La cifra de 1 MB era correcta antes de que subieran el tope, y el lexicon todavía registra el cambio en su propia descripción: "May be up to 2 MB, formerly limited to 1 MB." Las guías que publican 1 MB no se han actualizado desde entonces.
¿Cuántas imágenes caben en un post de Bluesky?
Cuatro, fijadas por "maxLength": 4 en el array de imágenes de app.bsky.embed.images. El lexicon más nuevo, app.bsky.embed.gallery, sube el techo de esquema a 20 mientras instruye a los clientes a aplicar un límite blando de 10.
¿Bluesky acepta PNG y WebP?
El blob de imagen de post declara "accept": ["image/*"], así que cualquier tipo MIME de imagen pasa la validación del protocolo. La app oficial convierte todo a JPEG antes de subirlo, así que un PNG que envías llega como JPEG. Los avatares y banners son más estrictos y solo aceptan image/png e image/jpeg.
¿Cuál es el límite de tamaño de avatar y banner en Bluesky?
Ambos son 1000000 bytes en app.bsky.actor.profile, la mitad del tope de imagen de post. Los avatares de generadores de feed y de listas en app.bsky.feed.generator y app.bsky.graph.list usan esa misma cifra de 1,000,000.
¿Por qué mi imagen subió bien pero mi post falló?
El endpoint de subida comprueba el límite de blob del servidor, que vale por defecto 5,242,880 bytes, y el tope de 2,000,000 del lexicon se comprueba más tarde, cuando un registro referencia el blob. Una imagen entre esas dos cifras sube y luego falla al publicar.
¿Bluesky comprime las imágenes después de subirlas?
La app comprime antes de subir, no después. La App View sirve luego derivados redimensionados desde su CDN para miniaturas y vistas a tamaño completo, y el lexicon anota que el archivo servido "May or may not be the exact original blob". El blob guardado en tu repositorio es lo que el cliente envió.
¿Bluesky comprime una imagen que ya pesa menos de 2.000.000 bytes?
El compositor de Bluesky ejecuta compressImage en cada imagen de post sin importar su tamaño de partida, y la recodifica a JPEG antes de iniciar la búsqueda de calidad. La función no comprueba el tamaño del archivo antes de empezar, así que incluso una exportación ya bien ajustada recibe una calidad JPEG nueva elegida por la app.
¿Por qué mi PNG transparente pierde el fondo al publicarlo en Bluesky?
El JPEG no tiene canal alfa, y la app de Bluesky convierte cada imagen de post a JPEG antes de subirla, así que el fondo transparente de un PNG queda relleno con un color sólido. Ocurre incluso si tu archivo original se veía bien, porque compressImage recodifica todas las imágenes sin excepción.
¿Bluesky conserva la relación de aspecto de mi archivo original?
La app rellena el campo aspectRatio a partir de la salida JPEG ya comprimida, no de tu archivo original, porque la relación se calcula después del redimensionado y la búsqueda de calidad. Ese campo guarda dos números enteros con un mínimo de 1, no una proporción decimal.
¿Existe un límite de caracteres para el texto alternativo en Bluesky?
El lexicón app.bsky.embed.images no fija ningún tope para el texto alternativo. La app oficial de Bluesky aplica su propia regla de cliente, MAX_ALT_TEXT = 2000, que es una decisión de la app y no un límite del protocolo, por lo que otros clientes pueden fijar el suyo.
AdaptlyPost
Prueba gratis de 7 días
Analíticas multiplataforma
Bandeja Social
Asistente con IA
Ponlo en práctica con AdaptlyPost
¿Te resultó útil este artículo?
¡Cuéntanos qué te parece!
Vernos más en Google
Un clic marca AdaptlyPost como fuente preferida y nuestros artículos aparecen más arriba en tus Noticias destacadas, el modo IA y los resúmenes con IA.
Antes de irte...
AdaptlyPost
Programa tu contenido en todas las plataformas
Gestiona todas tus cuentas de redes sociales en un solo lugar con AdaptlyPost.
Analíticas multiplataforma
Bandeja Social
Asistente con IA
Términos relacionados del glosario


Los dos registros detrás de un handle de dominio personalizado en Bluesky
Un handle de dominio personalizado en Bluesky necesita un registro: TXT en _atproto o texto plano en /.well-known/atproto-did. Los valores y las TLD vetadas.


Por qué el límite de caracteres de Threads cuenta emojis como bytes UTF-8
Son 500 caracteres, pero el límite de caracteres de Threads mide cada emoji por sus bytes UTF-8: un emoji de familia cuesta 25. Así se cuenta bien.


Por qué el límite de caracteres de la descripción de TikTok se mide en runas UTF-16
El límite de caracteres de la descripción de TikTok es de 2200 runas UTF-16 en video y 90 en un título de foto. Un emoji puede costar once runas.
Artículos Relacionados


Cómo funciona un generador de feeds de Bluesky, del lexicon al feed en vivo
Un generador de feeds de Bluesky es un servicio HTTPS que responde una consulta XRPC. Los lexicons, la entrada del documento DID, el JWT y los huecos.


Por qué la métrica cuentas que interactuaron en Instagram no equivale a interacciones
La métrica cuentas que interactuaron en Instagram cuenta cuentas únicas, no acciones, y los campos de la API ya no coinciden con los nombres de la app.


Por qué Bluesky facets byteStart byteEnd cuentan bytes, no caracteres
Los offsets Bluesky facets byteStart byteEnd cuentan bytes UTF-8, no índices UTF-16 de JavaScript. El aviso del lexicon, un ejemplo y código que acierta.

