Construí la infraestructura técnica de ⌘+P : The App Podcast como un desarrollador de apps construiría una app, no como un podcaster que apaña Spotify for Podcasters con cinta adhesiva. Esto es lo que ocurre cuando tratas el RSS como un producto.
Los primeros episodios de ⌘+P se grabaron en Podspace, en París: una cabina de verdad, micrófonos de verdad y un técnico de sonido de verdad que no finge entender cuando empiezas a hablar del bus AES frente a la salida de monitorización. La edición se hace en mi Mac con Final Cut Pro, porque, seamos sinceros: que un desarrollador de Apple monte su pódcast en Premiere sería como si un chef italiano le pusiera nata a la carbonara. La gente se da cuenta y juzga. Con razón.
Lo que subestimé es que la grabación y la edición representan aproximadamente el 20 % del trabajo. El resto es distribución. Y distribuir un pódcast en 2026 está mucho más lleno de trampas de lo que parece.
Este artículo es el análisis técnico a posteriori de la infraestructura que construí para ⌘+P: tres feeds RSS distintos, un CMS headless, una CDN personalizada, un codificador de vídeo adaptativo y una preferencia sin complejos por Apple Podcasts. Si estás pensando en lanzar un pódcast serio sin pasar por Acast ni Spotify for Podcasters, probablemente este sea el artículo más denso que leerás sobre el tema este año.
La apuesta: tratar el RSS como un producto
La pregunta que me ahorró seis meses de dar tumbos: ¿quiero que mi pódcast viva en la plataforma de otro o quiero que viva conmigo?
Spotify for Podcasters (antes Anchor) ofrece un trato aparentemente imbatible: subes tu .wav, generan el feed RSS, alojan el audio y lo envían a Apple Podcasts. Gratis. La pega, obviamente, es que el feed RSS les pertenece. El día que quieras cambiar de proveedor de alojamiento, te llevas tu catálogo, pero pierdes tus estadísticas, tus enlaces canónicos y, a veces, tu posición en los directorios que te indexaron a partir del feed original de Anchor. Acast sigue la misma lógica, con una UX más pulida y una factura mensual.
Elegí lo contrario. El feed RSS es un endpoint que controlo yo, en mi dominio, generado por mi código, a partir de mi fuente de verdad. Apple, Spotify, Pocket Casts, Castro, Overcast: todos se suscriben a mí. Si Spotify se vuelve hostil mañana, cambio dos líneas de XML, no todo mi proveedor de alojamiento.
Esa decisión tiene consecuencias en cadena. Si el RSS es mío, también tengo que hacerme cargo de todo lo que conlleva: el CMS, el almacenamiento de archivos de audio y vídeo, la codificación, la CDN, los capítulos, los metadatos de Podcasting 2.0 y las variantes para cada plataforma. Da más trabajo. También es infinitamente más instructivo, y la infraestructura resultante es sorprendentemente ligera.
La fuente de verdad: Hygraph
El contenido reside en Hygraph, un CMS GraphQL headless. Tengo un modelo PodcastEpisode que contiene todo lo que cabría esperar: temporada, número de episodio, invitados, capítulos, URL de audio y vídeo, notas del programa en texto enriquecido, fechas y los indicadores isPrivate y showOnHomepage. Los invitados son una entidad PodcastGuest independiente, con su propia biografía en texto enriquecido y su linkedinUrl, porque un mismo invitado puede volver, y duplicar una biografía en dos entradas es el tipo de pecado del que te arrepientes seis meses después. El vídeo reside en una entidad reutilizable Video a la que hace referencia PodcastEpisode; volveré sobre ello, porque acabó siendo fundamental.
El sitio que consume todo esto utiliza Next.js 16 App Router con Turbopack y Tailwind v4, desplegado en Clever Cloud con redespliegue mediante git push. La capa GraphQL utiliza Apollo Client. La internacionalización funciona mediante next-intl con siete configuraciones regionales (en, fr, de, it, nl, ar-AE, ar-SA) y localePrefix: 'as-needed'. Un detalle importante: el programa es francófono, así que, incluso cuando un visitante llega a /de/podcast, el RSS fuerza locales: ['fr', 'en'] en el servidor al consultar Hygraph. El RSS no es multilingüe: es bilingüe por naturaleza, y Apple Podcasts espera que sea así, independientemente de desde dónde hagas clic.
Almacenamiento: Clever Cloud Cellar detrás de Cloudflare
Los archivos multimedia (audio, vídeo y portadas) residen en Clever Cloud Cellar, su almacenamiento de objetos compatible con S3, detrás de una CDN de Cloudflare en cdn2.clementsauvage.me. La elección no es obvia, así que voy a justificarla.
Mux resulta tentador para todo: codificación, streaming y distribución. Pero, a la escala de un pódcast de vídeo que puede pesar 250 MB por episodio, la factura de Mux se vuelve desorbitada rápidamente al multiplicarla por el volumen de descargas del RSS. Cellar ofrece precios predecibles por gigabyte, compatibilidad nativa con solicitudes de intervalos de bytes (comprobado: Range: bytes=0-1023 devuelve un HTTP 206 limpio) y, como la aplicación ya está en Clever Cloud, la latencia entre servicios es insignificante. La compatibilidad con intervalos de bytes es innegociable, porque los clientes de pódcast nunca descargan un archivo de una sola vez: lo reproducen progresivamente y esperan poder reanudar la descarga.
Mux sigue formando parte del sistema, pero solo para el streaming web: HLS adaptativo mediante playbackId, reproducido por mux-player-react en la página del episodio. El vídeo incrustado en el sitio se beneficia de la escala de codificación profesional de Mux, mientras que el MP4 maestro H.264 de Cellar se utiliza exclusivamente para la distribución mediante RSS. Dos casos de uso, dos archivos, dos estrategias. Hay que pagar por más almacenamiento, pero cada archivo cumple su función sin concesiones.
El panel de importación: el contexto va primero
Tengo un endpoint privado, una herramienta que toma un .mp3 sin procesar de Final Cut y una portada JPEG, y genera en Hygraph un borrador del episodio listo para revisar.
La lección de UX que me costó un rediseño: el contexto debe ir antes que el contenido. La primera versión tenía los archivos arriba y los campos Temporada / Episodio / Tipo / Idioma abajo. Lógico desde el punto de vista del diseño de formularios. Catastrófico desde el punto de vista del pipeline, porque esos cuatro campos determinan la ruta de subida en Cellar (cmd-p-podcast/s{n}/episode-{m}/audio.wav). Si sueltas los archivos antes de elegir la temporada, o bien el servidor los rechaza, o bien hace una suposición y acabas con el episodio 12 almacenado en la carpeta del episodio 11. Invertí el orden: primero una cuadrícula de contexto de 2×2 y después la zona para soltar archivos. El formulario no acepta subidas hasta que se hayan rellenado esos cuatro campos. El error no volvió a producirse.
La subida en sí es S3 multipart con URL prefirmadas desde el navegador: el servidor genera URL prefirmadas para cada fragmento de 64 MB, el navegador hace PUT directamente en Cellar y el servidor recopila los ETag para ensamblar la subida multipart al finalizar. Un endpoint específico configura el CORS del bucket con ExposeHeaders: ETag porque, sin ello, el navegador no puede devolver los ETag y la finalización falla silenciosamente. Un detalle que no encontrarás en ninguna documentación generalista de S3.
Para los teasers, utilizo una convención de nombres específica: un sufijo alfanumérico de 7 caracteres generado a partir de un alfabeto de 55 caracteres (sin 0, 1, I, O, i, l ni o para evitar confusiones visuales). La clave se vuelve a generar cada vez que se selecciona el modo TEASER y se comparte entre los tres archivos de un teaser (audio/vídeo/portada). Esto permite que coexistan varios teasers para la misma temporada y el mismo episodio sin sobrescribirse, y que la URL siga siendo fácil de pronunciar por teléfono. Tres líneas de código que te evitan tener que decirle a tu invitado que has sobrescrito accidentalmente su teaser con el de otra persona.
El pipeline completo tras la subida: Mux ingiere el vídeo y genera un asset + un playback ID + una miniatura en el instante elegido. AssemblyAI transcribe el audio y genera capítulos automáticamente. En el panel de administración aparece una vista previa fácil de editar: descripción breve, notas del programa y capítulos (título / inicio / fin). Todo se puede editar antes de escribir en Hygraph. Al confirmar, creamos un borrador de PodcastEpisode con un UUID episodeGuid estable, la referencia al asset de Mux, la transcripción de AssemblyAI y los capítulos almacenados por separado del bloque de notas del programa; la interfaz del sitio y el JSON de <podcast:chapters> los exponen de forma independiente, así que fusionarlos sería un error de arquitectura que pagarías en cada actualización.
El RSS: tres feeds, tres estrategias
Aquí es donde la cosa se pone interesante. Apple Podcasts se considera la prioridad. Recibe el feed principal, el único que se publica en tiempo real y el único que incorpora todas las funciones de Podcasting 2.0. Spotify y el resto vienen después.
En concreto, hay tres endpoints:
/podcast/rss— feed principal, episodios publicados de inmediato, Podcasting 2.0 completo/podcast/rss/late— el mismo contenido con un retraso de 3 días/podcast/rss/spotify— feed solo de audio, con 3 días de retraso y cumplimiento estricto de los requisitos de Spotify
El retraso de 3 días es una decisión editorial deliberada. Apple Podcasts recibe el episodio el martes por la mañana. Spotify y los directorios secundarios lo reciben el viernes. Durante esas 72 horas, la audiencia que llega desde Apple Podcasts disfruta de una ventaja exclusiva. Es mi forma de recompensar a la plataforma que sostuvo el podcasting durante veinte años y, de paso, orientar a mis oyentes hacia el cliente que mejor respeta lo que realmente es un podcast: un archivo RSS, no una lista de reproducción algorítmica.
En el código, el filtro es !episode.isPrivate && isVisibleInDelayedFeed(...). La semántica de isPrivate me costó una buena media hora de confusión: un episodio privado se oculta del RSS, pero es visible en el sitio. Es justo lo contrario de lo que mi cerebro interpreta a primera vista, así que dejé un comentario en el código y lo anoté aquí para no volver a cometer el mismo error. Esto me permite publicar en el sitio un avance o un episodio exclusivo para mecenas sin contaminar Apple ni Spotify.
Qué incluye el feed de Apple
El feed principal adopta Podcasting 2.0 sin reservas. El espacio de nombres xmlns:podcast se declara en <channel> y emitimos:
<podcast:guid>— un UUID estable para el programa, desvinculado de la URL del feed<podcast:updateFrequency rrule="FREQ=WEEKLY;INTERVAL=2;BYDAY=TU" dtstart="2026-05-05T05:00:00Z">Cada dos martes</podcast:updateFrequency>— la cadencia oficial, interpretable por máquinas<podcast:person>para el presentador (Clément Sauvage, role="host", href, avatar de Cellar) y uno por cada invitado dinámico (role="guest", avatar de Hygraph, nombre + empresa en el contenido de texto)<podcast:chapters>con referencia a un JSON externo enapplication/json+chapters<podcast:alternateEnclosure>para ofrecer audio + vídeo en el mismo<item>
En cuanto al espacio de nombres de iTunes, emitimos el conjunto completo: itunes:author, itunes:type establecido en episodic, itunes:image (la portada obligatoria de 3000×3000; más sobre esto después), itunes:category establecido en Technology, itunes:explicit, itunes:owner con itunes:name y, fundamentalmente, itunes:email. En los elementos: itunes:episodeType (full o trailer), itunes:title, itunes:episode, itunes:season, itunes:duration en segundos y la imagen del episodio con la del canal como alternativa.
El <enclosure> principal apunta al vídeo MP4 H.264 cuando el episodio tiene uno, y el audio pasa a podcast:alternateEnclosure. Si no hay vídeo, el audio ocupa el <enclosure> principal. El tipo MIME se obtiene de la URL mediante una función mimeTypeFromUrl que detecta la extensión de la ruta ignorando las cadenas de consulta; Apple exige una extensión válida y tus URL de Cellar pueden incluir parámetros de consulta de firma que, sin esta precaución, no superarían la validación.
La trampa de la portada: 3000×3000 o nada
La portada la diseñé en Figma. Se ha convertido en mi herramienta predeterminada para prácticamente cualquier recurso visual estático: vectores limpios, exportaciones triviales en varias resoluciones y variantes (portada del programa, portadas de episodios y miniaturas de capítulos) que se mantienen sincronizadas mediante componentes. Y eso me lleva a la trampa.
Apple Podcasts exige una portada cuadrada, de 3000×3000 como mínimo y en JPEG. Primera exportación de Figma, primera subida, Apple la rechaza: 3000×3004. Cuatro píxeles de más en altura, porque un frame de Figma con un padding interno que no es perfectamente uniforme no se aprecia a simple vista, pero basta para hacer fallar el validador. Feed rechazado. Reajusté el frame a exactamente 3000×3000 en Figma, volví a exportar, volví a subirlo a cdn2.clementsauvage.me/cmd-p-podcast/cmdp-cover.jpg, comprobé con curl que devolvía accept-ranges: bytes y lo envié de nuevo. Aprobado.
Si solo aprendes una cosa de este artículo: comprueba las dimensiones píxel a píxel antes de enviarlo. Apple no te da un mensaje de error claro, solo un rechazo, y te deja haciendo conjeturas. Y configura explícitamente tu frame de Figma en 3000×3000, no en «más o menos cuadrado».
Capítulos en un JSON externo
En lugar de incluir los capítulos directamente en el XML, el estándar Podcasting 2.0 recomienda un archivo JSON externo. Tengo un endpoint /podcast/{slug}/chapters.json que sirve la especificación 1.2.0 de PodcastIndex:
{
"version": "1.2.0",
"title": "...",
"podcastName": "⌘+P: The App Podcast",
"author": "Clément Sauvage",
"chapters": [
{ "startTime": 0, "endTime": 90, "title": "Intro", "img": "...", "url": "..." }
]
}
Cascada de alternativas para la imagen: chapter.imageUrl de Hygraph; si no, la miniatura de Mux en t=startTime; y, si tampoco está disponible, la portada del episodio. El Content-Type se establece explícitamente en application/json+chapters; charset=utf-8 porque el valor predeterminado de Next, application/json, no lo reconocen todos los clientes. Caché s-maxage=900, stale-while-revalidate=3600 para no bombardear Hygraph con cada toque en Castro.
El doble <description> y <content:encoded>
Mientras que la mayoría de los proveedores se conforman con un <description> minimalista, yo emito ambos: un <description> en texto sin formato para garantizar la compatibilidad universal (incluidos los clientes antiguos que no interpretan HTML) y un <content:encoded> que contiene una versión HTML limpia del mismo contenido. Ambos incluyen notas del programa, una sección Cronología con marcas de tiempo en formato MM:SS o H:MM:SS cuando se supera una hora, una biografía resumida del presentador y biografías de cada invitado con el encabezado Con {name} — {role} en {company}.
Una pérdida de tiempo que quiero que te ahorres: el texto enriquecido de Hygraph extraído mediante .text aparecía con \n literales (la cadena barra invertida-n, no un salto de línea real) porque estaban almacenados con codificación JSON. Una función unescapeNewlines los convierte antes del renderizado. Sin ella, mi feed mostraba \n como texto visible en todos los clientes de podcast. Adiós, credibilidad.
El feed de Spotify: se elimina todo lo que le encanta a Apple
Spotify es exigente e idiosincrásico. Su especificación oficial prohíbe o ignora buena parte de lo que le encanta a Apple. Por tanto, mi feed /podcast/rss/spotify es una variante estricta:
- Sin espacio de nombres
podcast:*— Spotify no sabe qué hacer con él y prefiere que no exista - Sin
podcast:alternateEnclosure— la misma lógica - Sin
atom:link— Spotify prefiere que no esté itunes:ownerconitunes:email— necesario para que su equipo de soporte verifique el feed- Sin
itunes:titleredundante en los elementos - Solo audio — Spotify no admite vídeo mediante RSS, así que
<enclosure>siempre es MP3 o WAV - Capítulos en formato Podlove Simple Chapters (no Podcasting 2.0):
<psc:chapters version="1.1">
<psc:chapter start="0:00" title="..." href="..." image="..." />
</psc:chapters>
Con el espacio de nombres xmlns:psc="http://podlove.org/simple-chapters" añadido solo si el episodio tiene capítulos, porque declarar un espacio de nombres sin usar hace que algunos validadores se quejen.
Todo esto se gestiona mediante un parámetro mediaMode: 'default' | 'audio' que se pasa a getPodcastRss(...). El generador es único; los feeds son proyecciones diferentes. Sin duplicación de código ni divergencias entre versiones.
Codificación de vídeo para RSS: H.264 y nada más
Intenté usar HEVC porque es más eficiente, porque mi Mac Studio lo codifica por hardware y porque mis archivos son un 40 % más pequeños. Fue un error. HEVC no funciona en la vía RSS. Pocket Casts, Overcast y Castro no decodifican HEVC en el contexto de un pódcast. Apple Podcasts lo acepta mediante carga directa en Podcasts Connect, pero no mediante RSS. El resultado: un archivo que la mitad de tus oyentes no puede reproducir, sin ningún error claro.
La regla para RSS: MP4 H.264, AAC estéreo y punto. Esta es la receta de ffmpeg que utilizo:
ffmpeg -i source.mov \
-c:v libx264 -profile:v high -preset slow -crf 23 \
-vf "scale=1280:720" -pix_fmt yuv420p -movflags +faststart \
-c:a aac -b:a 256k -ar 48000 \
out.mp4
Algunas decisiones que no son evidentes:
- 720p, no 1080p ni 4K. Para primeros planos de personas hablando en conversaciones con poco movimiento, 1280×720 es el punto óptimo. El 4K es un desperdicio y el 1080p añade peso sin un beneficio perceptible.
- CRF 23 con preset slow en lugar de una tasa de bits fija. Tarda más en codificar, pero el control de la tasa es mejor y las escenas estáticas ahorran bytes automáticamente.
- AAC estéreo a 256 kbps — la recomendación de Apple; a 128 kbps, la voz se degrada de forma perceptible.
-movflags +faststartmueve el átomo moov al principio del archivo. Sin esta opción, el cliente de pódcast tiene que descargar el archivo entero antes de poder iniciar la reproducción. Con ella, la transmisión progresiva funciona desde los primeros kilobytes.-pix_fmt yuv420p— sin esta opción, ffmpeg puede generar yuv444p, que algunos reproductores rechazan. Seis caracteres que evitan horas de depuración.
Resultado concreto: un teaser pasó de 120 MB (exportación H.264 de FCP a 9,8 Mbps) a 26,4 MB, sin ninguna diferencia visible. Un episodio de 22 minutos ocupa unos 250 MB, una cifra razonable para una descarga RSS mediante datos móviles.
Y si utilizas Permute para procesar tus codificaciones por lotes: desmarca siempre «Allow copying of HEVC tracks». De lo contrario, la herramienta copia el flujo directamente y acabas con un MP4 que contiene HEVC, justo lo que querías evitar.
Tamaño de archivo en RSS y por qué Video.sourceSizeBytes
Un pequeño detalle que lo cambia todo para los clientes de pódcast: el atributo length de <enclosure> debe ser el tamaño exacto del archivo en bytes. Apple Podcasts lo utiliza para calcular la barra de progreso de la descarga. Si el valor es incorrecto o falta, algunos clientes muestran un progreso erróneo y otros se niegan directamente a descargarlo.
Ya tenía audioSizeBytes en PodcastEpisode, calculado durante la carga. Cuando añadí vídeo al <enclosure> principal, necesitaba el equivalente en la entidad Video: un nuevo campo opcional Video.sourceSizeBytes. Como PodcastEpisode ya tiene una relación video con Video, también añadí Video.sourceUrl a esa entidad en lugar de duplicar la URL en PodcastEpisode. El código RSS lee video.sourceUrl y video.sourceSizeBytes cuando el episodio tiene vídeo; de lo contrario, recurre a audioSizeBytes y a la URL del audio.
Los tipos de GraphQL se regeneraron después de cada migración de Hygraph (src/gql/graphql.ts y src/gql/gql.ts), y el código RSS gestiona ambos casos sin problemas. Cinco líneas adicionales en el generador, pero de esas que marcan la diferencia entre «funciona en mi máquina» y «funciona en Castro con 4G».
Producción asistida por IA: vídeo de introducción, tráiler y RSS
Hay tres áreas en las que dejo que los modelos generativos hagan el trabajo, y diría que esto también es lo que hace viable el stack para una sola persona.
El vídeo de introducción del programa —la pieza previa que abre cada episodio— partió de una sencilla foto de iPhone, procesada con el modelo de vídeo Happy Horse 1.0 para animarla. El resultado dura unos segundos, pero aporta al programa una identidad visual limpia, mientras que yo nunca habría llegado a publicar un diseño de movimiento decente empezando desde After Effects durante un fin de semana. El coste marginal es insignificante, el renderizado es coherente con la identidad y nadie pregunta «quién ha hecho tu introducción», que es el objetivo.
El tráiler de audio que se publica en redes sociales y que se distribuirá mediante <itunes:episodeType>trailer</itunes:episodeType> se produjo con Suno. No para la típica música de fondo (que seguiría prefiriendo componer o licenciar debidamente), sino para generar un breve teaser musical adaptado al formato de tráiler de pódcast: contundente, reconocible y con los derechos claros. El tema principal del programa sigue una lógica diferente y más artesanal, pero para un tráiler cuya vida útil es de unas semanas, Suno es exactamente la herramienta adecuada.
Y, sobre todo, Codex. La parte RSS de este stack —en particular, la coexistencia de los tres feeds, el cambio mediante mediaMode, las variantes de capítulos entre Podcasting 2.0 y Podlove Simple Chapters, el espacio de nombres dinámico por episodio y la conversión de las secuencias de escape de salto de línea— se escribió conjuntamente con Codex en modo de programación en pareja. No se generó y pegó sin más, sino que se escribió en colaboración: yo definía el contrato (qué debía producir cada feed, qué valida Podbase y qué rechaza Spotify), Codex proponía la mecánica del XML y yo iteraba sobre los casos límite que solo conoce una persona a la que realmente le han rechazado su feed. El resultado es código que he leído por completo y que firmo, pero no lo habría escrito tan rápido por mi cuenta. Afirmar lo contrario sería deshonesto, y he perdido un poco la paciencia con los desarrolladores que todavía fingen en 2026 que esto los ralentiza.
Por eso también este stack cabe en tres fines de semana y 12 € al mes. No se trata de ser más inteligente que antes, sino de disponer de herramientas que hacen viable el trabajo artesanal en solitario allí donde hace cinco años habría hecho falta un equipo.
Validación y depuración: lo que me salvó
Tres herramientas que recomiendo sin dudarlo:
Podbase valida tu feed según las especificaciones de Apple, Spotify y Podcasting 2.0. Detectó desde el principio que me faltaba el espacio de nombres podcast: (que había olvidado declarar), un falso positivo sobre la «falta de compatibilidad» con intervalos de bytes (el validador estaba probando un feed vacío porque todos mis episodios tenían isPrivate) y otro falso positivo sobre «el 0 % de los enclosures tiene una extensión válida» por el mismo motivo. Conclusión: valida con al menos un episodio público en el feed; de lo contrario, perseguirás errores que no existen.
curl + ffprobe + MediaInfo para verificar los enclosures: HTTP 200, content-type, accept-ranges, códecs de vídeo (H.264 frente a HEVC), dimensiones exactas (1280×720 frente a las que sean). Un curl -I sobre la URL de tu enclosure te dice en tres segundos si Cellar está respondiendo correctamente. Un ffprobe -v error -show_entries stream=codec_name,width,height te dice en dos segundos si tu archivo cumple los requisitos.
Logs de Clever Cloud + bun build en local para reproducir fallos en tiempo de ejecución. Dos ejemplos que me costaron una tarde cada uno:
- Un error
DYNAMIC_SERVER_USAGEprovocado por Apollo al hacer un fetch sin caché durante el renderizado de una ruta SSG. Solución:Promise.allSettledalrededor de la consulta a Hygraph en la ruta de la imagen OG, para que un error 5xx de Hygraph no impida generar la tarjeta. - Un fallo de Satori,
Cannot read properties of undefined (reading '256'), al renderizar la imagen OG dinámica con la fuente variable Rethink Sans. Satori no admite fuentes variables. Lección grabada en la memoria a largo plazo: nada de fuentes variables ennext/og. Sustituí el ⌘ renderizado como texto por un SVG inline y el fallo desapareció.
Decisiones estructurales, vistas en retrospectiva
Si tuviera que resumir la filosofía en cinco puntos:
SSG en todas partes salvo en el reproductor. La página /podcast y cada /podcast/[slug] se generan de forma estática mediante generateStaticParams. El reproductor de vídeo de Mux y la etiqueta <audio> son los únicos componentes de cliente que hacen streaming bajo demanda. SEO al máximo, páginas almacenables en caché en la CDN y tiempo hasta el primer byte inferior a 100 ms.
Hygraph como única fuente de verdad. Sin base de datos independiente, sin migraciones de esquema que gestionar, sin panel de administración personalizado que mantener. El administrador de importación crea borradores, yo valido manualmente cada episodio y Hygraph lo publica. Un único estado canónico.
Cellar como almacenamiento principal, Mux como lujo opcional. El máster MP4 H.264 reside en Cellar y alimenta el RSS. Mux tiene su propia codificación del mismo vídeo como HLS adaptativo para la web. Si Mux desapareciera mañana, el sitio perdería el streaming adaptativo, pero el pódcast seguiría publicándose sin interrupciones.
Podcasting 2.0 como elemento de primera clase, no como algo añadido a posteriori. Espacio de nombres podcast:, etiquetas de personas, JSON de capítulos, updateFrequency, alternateEnclosure. La inversión es baja, ya que de todos modos genero yo mismo el XML. El beneficio en Castro, Pocket Casts y Fountain es enorme.
Apple Podcasts primero, llevado a la práctica. 3 días de antelación respecto a Spotify. Todas las etiquetas de Podcasting 2.0. Portada de 3000×3000 perfecta al píxel. La lealtad a la plataforma que inventó el formato merece un esfuerzo técnico real, no solo un tuit amable (Cupertino, te costará una entrada dorada para la Dubdub, xxx)
Hacia dónde lleva esto
⌘+P no es un ejercicio de marketing para vender horas de consultoría, aunque soy consultor. Es el proyecto de un artesano que se pregunta si un solo desarrollador puede construir un pipeline de pódcast moderno y limpio sin depender de nadie, utilizando herramientas de 2026 en lugar de herramientas de 2018. La respuesta, después de dos meses abriéndome paso, es sí, pero solo si aceptas dos cosas. Que el RSS es un producto en sí mismo, no un archivo que generas al final. Y que la producción asistida por IA no es un atajo vergonzoso, sino una parte integral de lo que hace viable una operación en solitario: Figma para los elementos visuales, Happy Horse para crear el vídeo de introducción a partir de una foto de iPhone, Suno para el tráiler y Codex para la mitad del código RSS. Sin esas herramientas, no haría este pódcast. Con ellas, lo hago bien.
La próxima iteración probablemente incluirá transcripciones servidas mediante <podcast:transcript> (ya tengo el SRT de AssemblyAI, son tres líneas de XML), una localización al inglés del feed para el público anglófono y un panel de analítica que analice las solicitudes Range en Cellar para reconstruir las curvas de escucha de cada episodio. Sin Spotify Wrapped, sin Chartable, solo mis propios logs.
Si estás creando tu pódcast ahora mismo y dudas entre Acast y hacerlo tú mismo: el stack que acabo de describir requirió aproximadamente tres fines de semana de código y cuesta unos 12 €/mes en infraestructura (Clever Cloud + Cellar + nivel gratuito de Hygraph + nivel gratuito de Mux hasta cierto volumen). Es más que cero. También es la diferencia entre alquilar tu feed y ser su propietario.
El primer episodio de ⌘+P se estrena el martes, 5 de mayo de 2026. Si te interesan la tecnología, el producto, la artesanía del software o, sencillamente, las personas que hacen bien las cosas, suscríbete primero en Apple Podcasts; no porque sea mejor, sino porque llega tres días antes.
Y si tienes un proyecto excepcional, ponte en contacto conmigo. Innovar es lo que me mueve.
