Zainstalowałem EmDash CMS (wersja 0.1) od Cloudflare na Workers i sprawdziłem co dostaje
2 kwietnia 2026 Cloudflare ogłosił EmDash – open-source’owy CMS napisany w TypeScript, który ma być „duchowym następcą WordPressa”. Obietnice: sandboxowane pluginy, Portable Text zamiast HTML, wbudowany MCP server dla agentów AI, serverless na Cloudflare Workers, licencja MIT.
Zamiast czytać o tym co EmDash ma robić, zainstalowałem go na Cloudflare Workers i sprawdziłem, co faktycznie robi. Ten tekst to nie recenzja — to raport z instalacji i audyt SEO HTML-a który CMS generuje out of the box.
Co to jest EmDash i dlaczego mnie to obchodzi
EmDash to CMS zbudowany na Astro 6, napisany w TypeScript, zaprojektowany do pracy na Cloudflare Workers (D1 jako baza, R2 jako storage). Nie wykorzystuje ani linijki kodu WordPressa – stąd licencja MIT zamiast GPL.
Z perspektywy SEO trzy rzeczy przyciągnęły moją uwagę:
Pierwsza – architektura SSR na edge. Astro renderuje pełny HTML po stronie serwera, Cloudflare Workers serwuje go z najbliższego PoP. Żadnego client-side renderingu, żadnego hydration problemu, żadnego „chwila, muszę załadować JS, żeby pokazać content”. Googlebot dostaje gotowy HTML.
Druga – Portable Text. EmDash nie przechowuje contentu jako HTML w bazie (jak WordPress). Przechowuje go jako strukturalny JSON. To zmienia reguły gry jeśli chodzi o content portability i parsowanie treści przez AI agenty, ale o tym niżej.
Trzecia – x402. EmDash ma wbudowaną obsługę HTTP 402 Payment Required – mechanizm mikropłatności za content, projektowany z myślą o AI agentach, które pobierają treści. Żaden inny CMS tego nie ma natywnie.
Instalacja – dokumentacja vs rzeczywistość
Co naprawdę się dzieje, kiedy ktoś spoza zespołu Cloudflare próbuje postawić EmDash na Workers. Dokumentacja tej ścieżki praktycznie nie opisuje.
Node.js: wersja 18 nie wystarczy
Repo mówi „Node.js”. Nie mówi, która wersja. better-sqlite3 (zależność do lokalnego demo) wymaga kompilacji natywnej C++ i szuka Visual Studio Build Tools na Windowsie. Nie masz VS Build Tools? pnpm install pada.
Obejście: dodanie neverBuiltDependencies w package.json dla better-sqlite3. Ale to dopiero początek — sam build wymaga Node 20+, bo rolldown (bundler) używa styleText z node:util, które pojawiło się w Node 20.12. Na Node 18 dostajesz kryptyczny SyntaxError: The requested module 'node:util' does not provide an export named 'styleText'.
Nic nigdzie o tym w README.
Dynamic Workers: płatny plan wymagany
Deploy na Workers przechodzi gładko… do momentu, gdy wrangler zwraca:
In order to use Dynamic Workers, you must switch to a paid plan
Code language:JavaScript(javascript)
Dynamic Workers to mechanizm izolacji pluginów – kluczowa feature EmDash. Wymaga Workers Paid ($5/mies.). To nie jest problem finansowy tylko komunikacyjny. Cloudflare reklamuje EmDash jako free i open source, ale kluczowa funkcja wymaga płatnego konta. Na lokalnym Node.js sandbox pluginów w ogóle nie działa.
Route hardcoded na demo.emdashcms.com
Po pierwszym deployu wrangler zwraca error:
Could not find zone for'demo.emdashcms.com'Code language:JavaScript(javascript)
Konfiguracja wrangler.json generowana przy buildzie zawiera route do demo.emdashcms.com – domeny zespołu Cloudflare. Trzeba ręcznie usunąć sekcję routes i dodać "workers_dev": true. Ale plik generuje się przy każdym buildzie z wrangler.jsonc, więc poprawkę trzeba zrobić w źródle.
Auth: hardcoded pod wewnętrzny zespół Cloudflare
To jest najpoważniejszy problem. W astro.config.mjs demo Cloudflare:
Autoryzacja jest skonfigurowana pod Cloudflare Access zespołu CTO Cloudflare. Nikt spoza tej organizacji nie przejdzie. Efekt: panel admina się ładuje (to statyczny SPA), ale każdy request API zwraca 401 Unauthorized. Dashboard wygląda jakby działał, ale jest „martwy”.
Rozwiązanie: usunięcie providera access() z konfiguracji. Oczywiście nigdzie nie jest to udokumentowane.
Seed: brak ścieżki do inicjalizacji zdalnej D1
emdash seed działa lokalnie z SQLite. Na Cloudflare z D1? Brak udokumentowanej metody. Endpoint /_emdash/api/seed istnieje, ale zwraca CSRF error nawet z przeglądarki. Header, którego wymaga to X-EmDash-Request: 1 – znalazłem go dopiero analizując kod inline editing toolbara w wygenerowanym HTML.
Ostatecznie seed zadziałał po: usunięciu Cloudflare Access, resecie bazy D1, redeployu i wejściu na /admin – setup wizard odpalił się na czystej bazie.
Podsumowanie instalacji
Czas od git clone do działającego site’a: ~3 godziny z debugowaniem. WordPress: 5 minut. To v0.1 – ale różnica jest realna. Problem nie w tym, że EmDash CMS jest wczesny. Problem w tym, że demo Cloudflare jest skonfigurowane pod ich wewnętrzną infrastrukturę i nikt nie przetestował ścieżki „zewnętrzny developer (na Windowsie) chce to odpalić”.
Rzut oka na SEO: co generuje EmDash out of the box
Mam działającą instancję na emdash-demo.qbeczek.workers.dev. Sprawdziłem HTML kilku postów – zarówno nowo utworzonego (puste pola SEO) jak i zaseedowanego (wypełnione pola).
„EmDash generuje lepszy HTML out of the box niż WordPress bez pluginów i to nie jest komplement dla EmDash, tylko komentarz o tym jak nisko ustawił poprzeczkę WordPress przez 24 lata. OG tagi, canonical, JSON-LD natywnie, bez Yoasta to powinien być standard, nie feature.”
Jakub Sawa, SEO ekspert, fratreSEO.com
Co jest i działa poprawnie
Rendering. Pełny SSR. curl na URL posta zwraca kompletny HTML z contentem. Zero JavaScript-dependency do wyświetlenia treści. Googlebot dostaje to samo co przeglądarka. Tu EmDash jest wzorowy.
Meta tagi. Gdy pola SEO są wypełnione, EmDash generuje kompletny zestaw:
<title> w formacie {tytuł posta} | {nazwa serwisu} (na mojej wersji nie działa nadpisanie SEO title)
<meta name="description"> – z pola excerpt/SEO description
<link rel="canonical"> – pełny URL, poprawny
Open Graph: og:type, og:title, og:description, og:image, og:url, og:site_name, article:published_time, article:modified_time
Twitter Cards: twitter:card (automatyczny upgrade z summary na summary_large_image gdy jest obrazek), twitter:title, twitter:description, twitter:image
Ważne: gdy pola SEO są puste – EmDash nie wstawia pustych tagów. To poprawne zachowanie. Brak <meta name="description"> w moim testowym poście to nie bug CMS-a, tylko puste pole.
Structured Data. JSON-LD BlogPosting z headline, description, image, url, datePublished, dateModified, publisher (Organization), mainEntityOfPage. Schema jest osadzona w <head>, nie generowana przez JS.
Semantyczny HTML.<article>, <header>, <main>, <nav>, <aside>, <footer>, <time> z atrybutem datetime. Komentarze renderowane server-side – crawlowalne od razu.
URL structure. Czyste slugi: /posts/notes-on-simplicity. Bez trailing slash. Kategorie: /category/design. Tagi: /tag/webdev. Konfigurowalne przez Astro routing.
Taksonomie. Coś, z czym goły WP ma problem, tutaj jest out of the box.
Inne. RSS feed (/rss.xml linkowany w footerze). Sitemap deklarowana w robots.txt. Lazy loading na obrazkach (loading="lazy" + decoding="async"). Wbudowany live search z fallbackiem na /search?q=. Responsive images z aspect-ratio i max-width: 100%.
Czego brakuje
Schema author. W HTML jest byline („Guest Contributor”), ale w JSON-LD BlogPosting nie ma property author. Google wymaga author dla eligibility do Top Stories i artykułowych rich results. To jest duży brak.
Schema articleSection. Kategorie istnieją w HTML (sidebar), ale nie trafiają do structured data.
Breadcrumbs. Brak – ani w HTML, ani w Schema.
og:locale / hreflang. Config Astro ma zdefiniowane locales (en, fr, es z fallbackiem), ale zero outputu w <head>. Ani og:locale, ani <link rel="alternate" hreflang>.
Kontrola robots per-post. Brak <meta name="robots">. Domyślnie index/follow – OK, jest możliwość ustawienia w panelu noindex na konkretnym poście, ale u mnie nie zadziałało.
Heading hierarchy w sidebarze. Widgety (Search, Categories, Tags) używają <h3> bez parent <h2>. Między <h1> tytułu posta a <h3> widgetów jest dziura w hierarchii. Drobnostka, ale Lighthouse zgłasza.
Tabela porównawcza: EmDash vs WordPress
Feature
EmDash v0.1
WordPress 6.x
SSR / pełny HTML
Tak (Astro)
Tak (PHP)
Meta description
Tak (gdy wypełnione)
Wymaga pluginu (Yoast/RankMath)
Canonical
Tak
Tak (od WP 5.x)
Open Graph
Tak, komplet
Wymaga pluginu
Twitter Cards
Tak, z auto-upgrade
Wymaga pluginu
JSON-LD Schema
BlogPosting (bez author)
Wymaga pluginu
Sitemap
Tak (robots.txt)
Tak (od WP 5.5)
robots per-post
Tak (nie działa)
Wymaga pluginu
hreflang
Nie (mimo config)
Wymaga pluginu
Breadcrumbs schema
Nie
Wymaga pluginu
RSS
Tak
Tak
Inline editing
Tak (toolbar na froncie)
Tak (Gutenberg)
Heading hierarchy
Problematyczna w sidebar
Zależy od motywu
Wniosek: EmDash OOTB daje więcej niż goły WordPress bez pluginów. Meta tagi, OG, Twitter Cards, JSON-LD – to wszystko w WordPressie wymaga Yoasta lub RankMath. EmDash ma to natywnie. Ale brakuje fundamentów (author w schema, hreflang, breadcrumbs) które pluginy WP dawno rozwiązały.
Co interesujące z perspektywy AEO
Trzy rzeczy w EmDash nie mają odpowiednika w żadnym innym CMS-ie:
Portable Text. Content przechowywany jako JSON, nie HTML. To znaczy że AI agent parsujący treść EmDash nie musi interpretować DOM-a – dostaje strukturalny format z typowanymi blokami (paragraph, heading, image, code). Dla RAG pipelines to ogromna różnica między „wyciągnij tekst z HTML” a „przeczytaj JSON”. Konsekwencja: content łatwiej migrować, łatwiej transformować, łatwiej serwować w różnych formatach.
MCP Server. Każda instancja EmDash eksponuje Model Context Protocol server. Podłączasz Claude Desktop, Cursor albo dowolnego klienta MCP i zarządzasz contentem przez AI. Tworzenie postów, migracje, bulk operations – programowo, przez agenta. To nie jest feature dla redaktora. To jest feature dla developera, który buduje pipeline content automation.
x402 Payment Required. Natywna obsługa mikropłatności za content. AI agent requestuje stronę, dostaje 402 z ceną, płaci stablecoinem, dostaje content. Bez subskrypcji, bez formularzy. W świecie gdzie 60% ruchu wkrótce mogą generować AI agenty – to jest ciekawy business model. Pytanie, czy ktokolwiek będzie z tego korzystał w v0.1. Na razie czysta spekulacja.
Werdykt: dla kogo jest EmDash dzisiaj
Deweloperzy na Cloudflarestack, którzyy budują nowe projekty i chcą CMS z SSR, edge deployment i TypeScript end-to-end. Dla nich warto postawić demo, pobawić się, obserwować development.
Agencje SEO i content teamy: za wcześnie. Zero ekosystemu pluginów. Brak marketplace’u z motywami. Brak community. Jeden oficjalny motyw (blog). Problemy z seedem, auth, dokumentacją. To nie jest tool do produkcji dzisiaj.
SEO consultanci: warto znać architekturę. Klienci zaczną pytać. Architektura EmDash (SSR na edge, structured content, sandboxowane pluginy) to kierunek w którym idzie cała branża CMS. Nawet jeśli EmDash sam nie wygra, pattern który ustanawia jest istotny.
Matt Mullenweg skomentował: EmDashpowstał, żeby sprzedawać więcej usług Cloudflare. I ma rację – D1, R2, Workers, Dynamic Workers, Images, Stream – każda warstwa EmDash to binding do płatnego produktu CF. Ale to nie dyskwalifikuje architektury. WordPress też powstał w ekosystemie firm hostingowych, które na nim zarabiają.
Wersja 0.1. Dużo obietnic, trochę realnego kodu, sporo ostrych krawędzi. Ale HTML, który generuje jest solidny i to mówi coś o priorytetach zespołu.
Artykuł oparty na hands-on instalacji EmDash v0.1.0 na Cloudflare Workers, 4 kwietnia 2026. Instancja testowa: emdash-demo.qbeczek.workers.dev.
Jakub Sawa
Manager, Growth Hacker, ekspert SEO
Przygodę z internetem zacząłem w 1997 roku, od zakupu modemu. Przez 10 lat pracowałem w marketingu affilacyjnym online, głównie na rynku USA. Od 2008 roku byłem mocno związany z polskim rynkiem e-commerce. Jestem pasjonatem nowych technologii, z których korzystam na co dzień. Jestem właścicielem kilkunastu serwisów internetowych, praktykiem, aktywnie działającym w społeczności e-commerce i SEO. Tworzę i realizuję strategie wzrostu dla największych wydawców online w Polsce (Onet-RASP, Agora), zajmuje się konsultingiem i doradztwem w zakresie analityki, e-commerce oraz SEO/SEM.