Cuando conviertes una imagen a Base64, obtienes un data URI: una cadena como data:image/png;base64,iVBORw0KGgo… que puedes pegar directamente en el src de un HTML o en un url() de CSS. El navegador la decodifica en el acto y muestra la imagen sin descargas aparte. No hay archivo que alojar, ni petición extra.
¿Entonces deberías hacerlo? Esta es la regla corta. Incrusta una imagen como Base64 cuando sea pequeña (menos de unos 2 KB), cambie pocas veces y quieras ahorrarte una petición HTTP: piensa en iconos diminutos y logotipos. Para todo lo demás —imágenes grandes, cualquier cosa reutilizada entre páginas, cualquier cosa que quieras que el navegador guarde en caché— mantenla como un archivo de imagen normal. El problema es que Base64 hace que un archivo pese alrededor de un 33 % más, y una vez que ese texto queda incrustado en tu HTML o CSS ya no se puede guardar en caché por su cuenta.
Si quieres las cifras exactas de un archivo concreto, el conversor de Imagen a Base64 hace la codificación en tu navegador y muestra el aumento de tamaño preciso, así puedes decidir con datos reales en lugar de con una regla general. En lo que sigue verás qué es realmente ese data URI, las cuentas detrás del impuesto de tamaño, cuándo conviene incrustar y los casos en los que gana un archivo común.
Qué produce realmente “imagen a Base64”: el data URI
Convertir una imagen a Base64 no te da un archivo. Te da una sola cadena larga que sigue el formato de data URI definido en el RFC 2397 (consulta la referencia de URL data: de MDN). La cadena tiene tres partes:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…
└──┬─┘ └───┬───┘ └─┬──┘ └─────────┬──────────┘
data: MIME type marker the encoded image bytes
El tipo MIME le dice al navegador qué clase de imagen está decodificando. Los habituales para imágenes son image/png, image/jpeg, image/gif, image/webp, image/svg+xml e image/x-icon para los favicons. El marcador ;base64, indica que la carga que sigue es Base64 y no texto plano. Todo lo que va después de la coma es la imagen, vuelta a expresar como ASCII imprimible.
Esa última parte importa para la privacidad. La conversión se ejecuta enteramente en tu navegador mediante el método readAsDataURL de la API FileReader: nada se sube a un servidor. Puedes soltar una captura previa al lanzamiento, un diagrama interno o una ilustración inédita en la herramienta y ver cómo la pestaña Network se queda vacía. Para los mecanismos internos de cómo los bytes en bruto se convierten en esa cadena ASCII, entender Base64 cubre la codificación desde cero, y la guía completa de Base64 extiende esa misma idea de data URL a fuentes, PDF y otros tipos de archivo.
Un ejemplo real: un PNG transparente de 68 bytes
Aquí está el caso práctico más pequeño: un PNG transparente de 1×1, 68 bytes en disco, como un data URI completo:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==
Pega eso en la barra de direcciones de un navegador y verás (bueno, no verás, es transparente) cómo se renderiza una imagen válida con cero actividad de red. Fíjate en el == final: es relleno, al que llegaremos enseguida. Esto es también exactamente lo que parece el Base64 de texto, solo que aplicado a bytes de imagen en lugar de texto; si solo necesitas codificar o decodificar cadenas de texto plano, la herramienta de codificación/decodificación Base64 se encarga de ese caso.
El impuesto del 33 % de tamaño (y por qué se acumula)
Base64 trabaja en grupos fijos: cada 3 bytes de binario se convierten en 4 caracteres ASCII. Cuatro tercios es aproximadamente 1,33, de ahí sale la cifra del +33 %. Suma un byte o dos de relleno más el prefijo data:image/png;base64, y la sobrecarga es algo mayor para archivos diminutos. Un ejemplo concreto: un PNG de 9 KB pasa a unos 12 KB de texto.
¿Por qué exactamente de 3 a 4? Base64 usa un alfabeto de 64 caracteres: A–Z, a–z, 0–9, más + y /. Sesenta y cuatro símbolos son 6 bits de información por carácter. Los bytes binarios son de 8 bits cada uno. El mínimo común múltiplo de 6 y 8 es 24 bits, que son 3 bytes o 4 caracteres Base64, así que el codificador recorre la imagen de 24 bits en 24 bits. Cuando la longitud de la imagen no es un múltiplo exacto de 3, uno o dos caracteres = rellenan el grupo final. Esa es la matemática, y es fija: no hay ningún ajuste del codificador que reduzca el 33 %.
Ese 33 % es el coste visible. El coste oculto es que se acumula, y esta es la parte que casi todos los consejos de “simplemente incrústalo” se saltan:
- La imagen se vuelve a descargar cada vez que cambia el archivo que la contiene. Un
logo.pngexterno es su propio recurso. Incrústalo enstyles.cssy ahora cada edición de esa hoja de estilos —un ajuste de color, una regla nueva— invalida también la caché de la imagen. Los visitantes vuelven a descargar la imagen que ya tenían. - No se puede guardar en caché de forma independiente. Un archivo de imagen normal se descarga una vez y se reutiliza en cada página y en cada visita. Un data URI incrustado es parte del documento, así que se envía de nuevo en cada página que lo incluya y en cada fallo de caché de ese documento.
- El CSS bloquea el renderizado. El navegador no pintará nada hasta tener el CSS. Mete un data URI grande en una hoja de estilos y habrás agrandado un recurso que bloquea el renderizado, retrasando el primer pintado de toda la página.
¿Gzip o brotli anulan ese 33 %?
En parte, no del todo. El texto Base64 es lo bastante repetitivo como para que gzip y brotli lo compriman bien, recuperando buena parte del inflado en la transferencia. Pero dos cosas siguen siendo ciertas. Primero, el Base64 comprimido suele ser todavía un poco mayor que el binario original comprimido, porque le has entregado al compresor un punto de partida menos eficiente. Segundo —y este es el punto más importante— la compresión no hace nada respecto a la caché ni al bloqueo del renderizado. Un data URI más pequeño en la transferencia sigue volviéndose a descargar con su archivo anfitrión y sigue sin poder guardarse en caché por sí solo.
Dicho de otro modo, comprimir no es lo mismo que eliminar el coste de incrustar. Si la diferencia entre minificar, comprimir con gzip y con brotli te resulta confusa, la guía de minificación de código explica cómo se apilan esas capas, y por qué exprimir los bytes nunca arregla el problema de caché que crea la incrustación.
Cuándo usar una imagen en Base64 (la matriz de decisión)
Toda la decisión se reduce a un puñado de factores, puestos uno al lado del otro:
| Factor | Inclínate por incrustar (Base64) | Inclínate por un archivo normal |
|---|---|---|
| Tamaño | Menos de ~2 KB (verde) | Más de ~10 KB (rojo); de 2 a 10 KB es cuestión de criterio (ámbar) |
| Reutilización | Una página, uno o dos sitios | Repetida en muchas páginas |
| Frecuencia de cambio | Casi nunca cambia | Se edita a menudo |
| Contexto | Correo HTML, widget o bookmarklet autónomo, carga JSON/API, un icono crítico sobre el pliegue que valga una petición ahorrada | Imágenes de contenido, recursos compartidos y cacheables |
Esos umbrales de tamaño no son arbitrarios: reflejan la insignia tipo semáforo integrada en el conversor de Imagen a Base64: verde por debajo de 2 KB, ámbar hasta 10 KB, rojo por encima. La herramienta lee tu archivo real y te dice en qué tramo cae.
Una regla general sencilla
Si recuerdas una sola frase, que sea esta: por debajo de ~2 KB y usada en solo uno o dos sitios, incrustar suele compensar; por encima de ~10 KB o reutilizada entre páginas, un archivo normal cacheado casi siempre gana. El tramo medio de 2 a 10 KB es donde sopesas la petición ahorrada frente a la caché perdida para tu situación concreta.
Los buenos encajes en detalle
Algunos casos en los que Base64 se gana de verdad su sitio:
- Correo HTML. Muchos clientes de correo bloquean por defecto las imágenes alojadas externamente por privacidad, lo que rompe cualquier diseño que dependa de un logotipo remoto. Un pequeño data URI incrustado se renderiza al instante sin petición al servidor. Limítalo a logotipos e iconos; nunca incrustes una fotografía en un correo.
- Widgets y bookmarklets autónomos. Un bookmarklet o un widget incrustable tiene que funcionar con cero dependencias externas. Incrustar sus iconos lo mantiene todo en un único archivo que puedes soltar donde quieras.
- Cargas JSON y de API. Enviar una miniatura dentro de un documento JSON o un archivo de configuración a veces es la opción más limpia: un solo viaje de ida y vuelta, un solo objeto, sin una segunda petición que cablear.
- Un icono crítico sobre el pliegue. Cuando un logotipo diminuto forma parte de tu Largest Contentful Paint y quieres quitarle una petición a la ruta crítica, incrustar puede ayudar, siempre que sea de verdad diminuto.
Un patrón une todo esto: cada caso es uno en el que el recurso viaja junto con otra cosa y de otro modo necesitaría su propio canal de entrega. Un correo no puede depender de tu CDN. Un bookmarklet no tiene un segundo archivo que buscar. Una respuesta JSON es una sola carga. En cada uno, la alternativa a incrustar no es “un archivo cacheado” sino “una imagen que falta”, lo que cambia por completo el cálculo. Así que la pregunta no es solo “¿es pequeña?”, sino “¿es siquiera una opción tener un archivo separado aquí?”.
Cuándo NO incrustar: caché, carga diferida y Core Web Vitals
La otra cara es más larga, porque incrustar desactiva en silencio varias cosas que el navegador hace bien.
Pierdes la caché independiente. Esto duele más en los visitantes que vuelven. Una imagen normal se queda en su caché tras la primera visita y carga al instante para siempre. Una imagen incrustada no tiene entrada de caché independiente: viaja con el documento cada vez, así que un visitante recurrente paga el coste en bytes una y otra vez.
Pierdes la carga diferida. El atributo loading="lazy" deja que el navegador posponga las imágenes que están por debajo del pliegue hasta que el usuario se acerca a ellas al desplazarse. Un data URI se analiza y se “descarga” en el instante en que se lee el HTML, así que no hay nada que posponer. Incrusta una docena de imágenes bajo el pliegue y habrás forzado a todas a la carga inicial.
Agrandas los recursos que bloquean el renderizado. Como ya se dijo, un data URI dentro del CSS engorda un recurso que bloquea el primer pintado. Cuanto más grande sea esa hoja de estilos, más tiempo se queda la página en blanco.
Decodificar cuesta más en el móvil. Un data URI se decodifica de Base64 cada vez que carga su documento, y en móviles de gama baja ese trabajo de CPU se acumula; además los bytes nunca llegan a la caché de disco del navegador, así que una imagen pesada incrustada se vuelve a decodificar en cada visita, en lugar de cachearse y decodificarse una sola vez como un archivo normal.
También hay una razón histórica por la que este consejo ha cambiado. El argumento original a favor de incrustar, defendido a viva voz en la era de HTTP/1.1, era reducir peticiones: cada conexión podía buscar un recurso a la vez, así que una página con 40 iconos pequeños pagaba 40 viajes de ida y vuelta. HTTP/2 cambió eso al multiplexar muchas peticiones sobre una sola conexión, lo que abarató los archivos pequeños adicionales. El gran beneficio de incrustar —menos peticiones— se evaporó en su mayor parte, mientras que los costes —caché perdida, sin carga diferida, archivos más grandes que bloquean el renderizado— se quedaron. Si lees artículos antiguos entusiasmados con los sprites en Base64, sopésalos frente al protocolo que tu sitio realmente usa hoy.
El ángulo de Core Web Vitals
Incrustar corta por los dos lados en el LCP (Largest Contentful Paint). Para una imagen pequeña sobre el pliegue que es el elemento LCP, quitar una petición puede adelantar un poco el LCP. Pero incrusta una imagen grande y haces lo contrario: retrasas el documento o la hoja de estilos en la que vive, empujando el LCP más tarde para toda la página. El umbral de tamaño decide hacia qué lado se inclina.
Para el CLS (Cumulative Layout Shift), incrustar no cambia nada de la regla básica: una imagen sigue necesitando width y height explícitos (o una caja con relación de aspecto) para que el navegador pueda reservar el espacio antes de renderizarla. Un data URI sin dimensiones desplaza el diseño exactamente igual que una imagen remota sin dimensiones.
Una palanca mejor que incrustar suele ser reducir el origen. Comprimir una imagen antes de codificarla hace más pequeños tanto el archivo como cualquier data URI resultante: la guía de compresión de imágenes en navegador frente a Node explica cómo hacerlo del lado del cliente o en un paso de compilación, y WebP vs AVIF vs JPEG te ayuda a elegir un formato que sea pequeño desde el principio.
Cómo incrustar imágenes en HTML, CSS, Markdown y JSON
Una vez que tienes un data URI, así es como cae en cada contexto. Estos son los cuatro fragmentos listos para pegar que el conversor de Imagen a Base64 genera por ti.
HTML — pega el URI en cualquier src:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…" alt="logo">
CSS — envuélvelo en url() para un background-image (este es el patrón canónico de imagen base64 en CSS):
.icon {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0i…");
}
Markdown — un enlace de imagen autónomo para READMEs, issues de GitHub y notebooks donde no puedes alojar un archivo:

JSON — un recurso incrustado dentro de una carga de API o de configuración:
{ "icon": "data:image/png;base64,iVBORw0KGgo…" }
Los cuatro funcionan en cualquier lugar donde se acepte una URL: img src, background de CSS, mask-image, incluso un <link> de favicon. Todos los navegadores modernos admiten el esquema data:.
Generarlos rápido
Construir estos a mano es propenso a errores: un tipo MIME equivocado o un salto de línea perdido y la imagen falla en silencio al renderizar. Suelta tu archivo en el conversor de Imagen a Base64 y produce los cuatro fragmentos con sus propios botones de copiar, además del aumento de tamaño exacto para que sepas de antemano si el recurso merece estar incrustado.
SVG: el caso especial donde Base64 suele perder
SVG rompe la lógica habitual, porque SVG es texto, no binario. Base64 existe para hacer que los datos binarios sean seguros como texto, pero SVG ya es texto XML. Codificarlo como Base64 solo infla una cadena que no necesitaba codificación, y la vuelve ilegible en el proceso. Así que para SVG en concreto, Base64 es casi siempre la elección equivocada.
Compara tres formas de incrustar el mismo icono:
/* 1. Data URI Base64: añade el impuesto del 33 % a un texto que no lo necesitaba */
.a { background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0i…"); }
/* 2. Data URI codificado como URL: codifica con porcentaje un puñado de caracteres, sin impuesto del 33 % */
.b { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'…%3C/svg%3E"); }
/* 3. <svg> en línea directamente en el HTML: totalmente estilizable con CSS */
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path d="M12 2 L22 22 H2 Z" fill="currentColor" />
</svg>
La opción 2 (codificación de URL) suele ser más pequeña que la opción 1, sigue siendo legible y comprime mejor. Solo codificas con porcentaje los caracteres que romperían el URI —<, >, # y las comillas—, dejando legible el resto. El enfoque del codificador/decodificador de URL está documentado en la propia herramienta; recurre al SVG en Base64 solo cuando un pipeline de compilación lo exija específicamente.
Por qué un <svg> en línea suele ganar a un icono PNG en Base64
Si estás eligiendo entre un icono PNG codificado en Base64 y un <svg> en línea, el SVG normalmente gana en todos los ejes. Escala a cualquier tamaño sin difuminarse, no lleva el impuesto del 33 % y —a diferencia de cualquier data URI— puedes estilizarlo con CSS, animarlo y recolorearlo con currentColor. Un PNG en Base64 es un bloque de resolución fija que no puedes tocar una vez codificado. Reserva el Base64 raster para los casos en los que de verdad necesites una fotografía o una captura de pantalla raster en línea.
Decodificar en sentido contrario: de Base64 de vuelta a una imagen
El problema inverso es igual de común: tienes una cadena Base64 —sacada de una respuesta de API, una línea de log, una columna de base de datos o una hoja de estilos que estás depurando— y necesitas ver la imagen real.
Dos detalles hacen tropezar a la gente. Primero, Base64 en bruto frente a un data URI completo. Un data URI completo (data:image/png;base64,…) lleva su propio tipo MIME; una carga desnuda (iVBORw0KGgo…) no. Para renderizar una carga desnuda o bien le antepones un prefijo data: correcto, o dejas que una herramienta infiera el formato a partir de los primeros bytes: iVBORw0KGgo significa PNG, /9j/ significa JPEG, R0lGOD significa GIF.
Segundo, el ajuste de línea. El Base64 procedente de correos o de herramientas más antiguas suele venir ajustado a 76 caracteres según el RFC 2045. Esos saltos de línea deben eliminarse antes de decodificar, o la cadena será inválida en un atributo HTML o en un url().
En el navegador puedes pasarle un data URI completo directamente a una <img>:
<img src="data:image/png;base64,iVBORw0KGgo…" alt="decoded">
En el servidor, Node reconstruye el archivo a partir de la carga:
import { writeFileSync } from "node:fs";
const b64 = "iVBORw0KGgoAAAANSUhEUgAA…"; // raw payload, no data: prefix
writeFileSync("output.png", Buffer.from(b64, "base64"));
Para una vía sin código —pega una cadena (con o sin el prefijo, saltos de línea incluidos), previsualízala, lee sus dimensiones y tipo MIME, y descarga un PNG, JPG, GIF o SVG real— usa el conversor de Base64 a Imagen. Elimina los espacios en blanco, tolera la ausencia de prefijo y detecta el formato a partir de los bytes mágicos automáticamente.
Una comprobación de cordura que merece la pena hacer en una imagen decodificada: mira sus dimensiones reportadas. Si sacaste una cadena de un archivo que contenía varias y el resultado es de 1×1, probablemente agarraste un píxel de seguimiento en lugar del recurso que querías. Y recuerda que decodificar es puramente mecánico y sin pérdidas: un PNG en Base64 vuelve siendo exactamente el mismo PNG, byte por byte, sin recompresión. Lo único que cambió por el camino fue el contenedor: una cadena de texto a la salida, un archivo binario a la vuelta.
Preguntas frecuentes
¿Debería convertir mis imágenes a Base64?
Solo cuando merezca la pena: iconos o logotipos pequeños (menos de ~2 KB) que cambian pocas veces y donde ahorrarse una petición HTTP importa, además del correo HTML, los widgets autónomos y las cargas JSON. Las imágenes grandes o cualquier cosa reutilizada entre páginas casi siempre deberían seguir siendo archivos normales, para que conserves la caché y la carga diferida.
¿Cuánto más grande hace Base64 una imagen?
Alrededor de un +33 %. Base64 codifica cada 3 bytes de binario como 4 caracteres ASCII, más un poco de relleno y el prefijo data:. Un PNG de 9 KB pasa a unos 12 KB de texto. Para convertir una imagen a Base64 y ver el aumento exacto de tu archivo, la herramienta reporta la cifra precisa en su barra de metadatos.
¿Hace Base64 que las imágenes carguen más rápido?
Para un icono muy pequeño sobre el pliegue puede hacerlo, al ahorrar el viaje de ida y vuelta de una petición. Para imágenes más grandes o reutilizadas suele ser más lento: pierdes la caché independiente, no puedes cargarla de forma diferida e incrustarla en el CSS agranda un recurso que bloquea el renderizado. El tamaño es el factor decisivo.
¿Puedo usar una imagen en Base64 en CSS?
Sí: background-image: url("data:image/png;base64,…"). Está bien para iconos diminutos. Solo recuerda que el data URI pasa a formar parte de la hoja de estilos, así que todo el archivo se vuelve a descargar cada vez que cambia el CSS, y la imagen no se puede guardar en caché por separado de él.
¿Debería usar SVG o Base64 para los iconos?
Prefiere un <svg> en línea o un data URI de SVG codificado como URL. SVG es texto, escala limpiamente y no lleva el impuesto del 33 %, así que suele ser más pequeño que un PNG en Base64 y puedes estilizarlo con CSS. Recurre a Base64 solo cuando necesites específicamente un icono raster.
¿Cómo convierto una cadena Base64 de vuelta a una imagen?
En el navegador, suelta un URI completo data:image/…;base64,… en un <img src>. En un servidor, usa Buffer.from(b64, "base64") para escribir el archivo. Una carga en bruto necesita que se le añada un prefijo data:, y las cadenas con ajuste de línea necesitan que se eliminen primero sus saltos de línea. La herramienta de Base64 a Imagen se encarga de todo eso y te deja descargar el resultado.