[{"data":1,"prerenderedAt":252},["ShallowReactive",2],{"blog-alternates-\u002Fen\u002Fdooh-platform-on-cloudflare":3,"blog-nav-facets-en":6,"blog-post-en-dooh-platform-on-cloudflare":11},{"en":4,"pt":5},"\u002Fen\u002Fdooh-platform-on-cloudflare","\u002Fplataforma-dooh-cloudflare-native",{"populatedCategories":7,"authorCount":10},[8,9],"engenharia","dooh",1,{"post":12,"authorIndex":212,"counterpartSlug":209,"related":218},{"id":13,"title":14,"authors":15,"body":17,"category":8,"cover":190,"description":193,"discussionUrl":194,"draft":195,"extension":196,"featured":195,"highlights":194,"meta":197,"navigation":198,"ogImage":191,"path":199,"publishedAt":200,"seo":201,"slug":202,"sourceHash":194,"stem":203,"tags":204,"translate":198,"translatedFrom":208,"translationKey":209,"translationStatus":210,"updatedAt":194,"__hash__":211},"posts_en\u002Fen\u002Fposts\u002Fplataforma-dooh-cloudflare-native.md","Why Lucimark runs entirely on Cloudflare",[16],"paulo-ramires",{"type":18,"value":19,"toc":182},"minimark",[20,24,27,32,35,69,72,76,91,94,97,122,129,132,136,149,155,161,165,168,179],[21,22,23],"p",{},"Every DOOH platform solves the same basic problem: a screen somewhere needs to know what to play, right now, even when that location's internet drops three times a day. From there, the decisions diverge sharply.",[21,25,26],{},"Ours was to run everything on Cloudflare's edge. No application server, no third-party managed queue, no Docker anywhere — not even in development.",[28,29,31],"h2",{"id":30},"the-shape-of-it","The shape of it",[21,33,34],{},"Four pieces do the heavy lifting:",[36,37,38,46,52,58],"ul",{},[39,40,41,45],"li",{},[42,43,44],"strong",{},"Workers"," serve the whole API (Hono). No player request travels to a fixed datacenter: it is answered at the point of presence nearest the screen.",[39,47,48,51],{},[42,49,50],{},"D1"," holds the global catalogue — tenants, users, the player directory.",[39,53,54,57],{},[42,55,56],{},"R2"," holds the media. No egress cost, which matters when every screen pulls the same video files.",[39,59,60,63,64,68],{},[42,61,62],{},"Durable Objects"," hold each customer's state. One ",[65,66,67],"code",{},"TenantDO"," per organization, with SQLite embedded.",[21,70,71],{},"The fourth is the one that shapes everything else.",[28,73,75],{"id":74},"one-durable-object-per-customer","One Durable Object per customer",[21,77,78,79,82,83,86,87,90],{},"The normal instinct is a ",[65,80,81],{},"playlists"," table with a ",[65,84,85],{},"tenant_id"," column and a ",[65,88,89],{},"WHERE"," clause on every query. It works, and it is where almost every SaaS starts.",[21,92,93],{},"We went the other way: each organization gets its own Durable Object, with its own database. That customer's playlists, schedules, proof-of-play records and assets live inside it, and nowhere else.",[21,95,96],{},"That buys three things at once:",[98,99,100,110,116],"ol",{},[39,101,102,105,106,109],{},[42,103,104],{},"Isolation by construction."," No query can leak data across customers, because there is no shared table to leak from. The classic bug of forgetting ",[65,107,108],{},"WHERE tenant_id"," stops being possible.",[39,111,112,115],{},[42,113,114],{},"Coordination without a queue."," A DO is single-threaded by definition. When ten screens belonging to the same customer reconnect at once after a power cut, they talk to the same object, in order. We need no distributed lock for any of it.",[39,117,118,121],{},[42,119,120],{},"Locality."," The object migrates toward whoever uses it most.",[21,123,124,125,128],{},"The cost is real and worth stating: you lose the global query. \"How many screens are active across the whole platform?\" stops being a ",[65,126,127],{},"SELECT COUNT(*)"," and becomes a fan-out, or a projection you maintain deliberately. Every question that crosses customers now takes explicit work.",[21,130,131],{},"For our case, it was worth it. The questions that matter day to day — did this playlist change, is this screen alive, what played on it yesterday — all sit inside a single customer.",[28,133,135],{"id":134},"what-hurt","What hurt",[21,137,138,141,142,144,145,148],{},[42,139,140],{},"Migrations inside the DO."," Migrating one central database is an operation; migrating N databases, each waking up whenever its customer appears, is a different one. Our rule today is strict: SQL running at ",[65,143,67],{}," boot is DDL only, and it must be cheap. Any heavy backfill goes to an alarm or ",[65,146,147],{},"waitUntil",", off the critical path. We learned that the usual way — a boot that got too slow.",[21,150,151,154],{},[42,152,153],{},"Per-request CPU limits."," Workers are not the place to transcode video. Nothing CPU-heavy runs inline; it either gets its own service or becomes a Workflow.",[21,156,157,160],{},[42,158,159],{},"Observability."," State spread across thousands of objects does not show up on a dashboard by itself. Projecting what matters outward takes deliberate effort.",[28,162,164],{"id":163},"what-we-never-had-to-build","What we never had to build",[21,166,167],{},"The easiest part to underestimate is what disappears from the backlog.",[21,169,170,171,174,175,178],{},"We have no server to scale, no cluster to patch, no TLS certificate to renew, no CDN to configure in front of the media. ",[65,172,173],{},"wrangler dev"," brings the whole stack up on a developer's machine — no ",[65,176,177],{},"docker compose",", no local Postgres, no six containers to remember to tear down.",[21,180,181],{},"For a small team running a screen network that has to stay up, that is the decision that pays the most.",{"title":183,"searchDepth":184,"depth":184,"links":185},"",2,[186,187,188,189],{"id":30,"depth":184,"text":31},{"id":74,"depth":184,"text":75},{"id":134,"depth":184,"text":135},{"id":163,"depth":184,"text":164},{"src":191,"alt":192},"\u002Fimg\u002Fposts\u002Fplataforma-dooh-cloudflare-native\u002Fplataforma-dooh-cloudflare-native-cover.png","Illustration of a distributed screen network around abstract layers of compute, database, media, and state.","Workers, D1, R2 and one Durable Object per customer. What we gained, what hurt, and why there is no Docker anywhere in our stack.",null,false,"md",{},true,"\u002Fen\u002Fposts\u002Fplataforma-dooh-cloudflare-native","2026-08-12",{"title":14,"description":193},"dooh-platform-on-cloudflare","en\u002Fposts\u002Fplataforma-dooh-cloudflare-native",[205,206,207],"cloudflare","architecture","durable-objects","pt","plataforma-dooh-cloudflare-native","human","Hqg_j8WSVTK3sAZ3XL3RZK3Z3HmmJk2HEsu_autKyKo",{"paulo-ramires":213},{"handle":16,"name":214,"role":215,"avatar":216,"description":217},"Paulo R.","Founder and CTO","\u002Fimg\u002Fauthors\u002Fpaulo-ramires.jpg","Founder of Lucimark. Builds the platform end to end — from the Android player on the screen to the Workers serving the API.",[219,234],{"path":220,"title":221,"description":222,"slug":223,"translationKey":224,"category":8,"tags":225,"authors":228,"publishedAt":229,"updatedAt":194,"draft":195,"featured":195,"cover":230,"ogImage":231,"discussionUrl":194,"translationStatus":210,"readingMinutes":233},"\u002Fen\u002Fposts\u002Fmudanca-schema-alarm-30s-noite-bilhao-linhas","A schema change, a 30-second alarm, and a billion-row night","How a Proof of Play migration on Cloudflare Durable Objects became an unbounded storage loop — and the radar we built so the next one cannot hide.","schema-change-30-second-alarm-billion-row-night","schema-change-do-storage-storm",[205,207,226,227],"proof-of-play","cost-observability",[16],"2026-09-04",{"src":231,"alt":232},"\u002Fimg\u002Fposts\u002Fmudanca-schema-alarm-30s-noite-bilhao-linhas\u002Fmudanca-schema-alarm-30s-noite-bilhao-linhas-cover.png","Illustration of a schema node, alarm pulses, and an amber data storm against a dark background.",15,{"path":235,"title":236,"description":237,"slug":238,"translationKey":239,"category":9,"tags":240,"authors":245,"publishedAt":246,"updatedAt":194,"draft":195,"featured":198,"cover":247,"ogImage":248,"discussionUrl":194,"translationStatus":210,"readingMinutes":251},"\u002Fen\u002Fposts\u002Frede-5-telas-receita-custos-payback-dooh","Can a 5-screen network make money? Revenue, costs and payback for a DOOH operation","How much can a small 5-screen DOOH network bill? See public market references, investment, costs, advertisers needed and payback scenarios.","5-screen-network-revenue-costs-payback-dooh","rede-5-telas-receita-custos-payback-dooh",[9,241,242,243,244],"dooh-network","indoor-media","payback","revenue",[16],"2026-09-05",{"src":248,"alt":249,"credit":250},"\u002Fimg\u002Fposts\u002Frede-5-telas-receita-custos-payback-dooh\u002Fpraca-comercial-conectada-ao-amanhecer.jpg","Small digital media network connecting screens across different commercial venues","A small network can share infrastructure and inventory across different commercial points.",9,1788649408701]