[{"data":1,"prerenderedAt":567},["ShallowReactive",2],{"blog:/blog/migrate-from-firebase-to-nolag":3},{"id":4,"title":5,"author":6,"body":7,"category":556,"date":557,"description":558,"excerpt":559,"extension":560,"meta":561,"navigation":185,"path":562,"readTime":563,"seo":564,"stem":565,"__hash__":566},"blog/blog/migrate-from-firebase-to-nolag.md","Migrate from Firebase to NoLag","Henco Burger",{"type":8,"value":9,"toc":547},"minimark",[10,14,19,31,35,63,67,147,151,310,314,494,497,501,518,522,543],[11,12,13],"p",{},"Firebase Realtime Database and Firestore give you realtime by syncing stored documents and firing client listeners when the data changes. NoLag takes a different approach: explicit publish and subscribe over topics. That difference matters for migration, so let us be clear up front about what to move and what to keep.",[15,16,18],"h2",{"id":17},"what-to-migrate-and-what-not-to","What to migrate, and what not to",[11,20,21,22,26,27,30],{},"NoLag is a ",[23,24,25],"strong",{},"messaging layer, not a database",". If you use Firebase purely as a realtime signal, presence, or message bus, NoLag replaces that cleanly and gives you more control over delivery. If you use Firebase as your ",[23,28,29],{},"system of record",", keep a database. Migrate the realtime and pub/sub usage to NoLag, and let your data live wherever suits you. Many teams end up with NoLag for the live layer and a database of their choice behind it.",[15,32,34],{"id":33},"why-teams-move-the-realtime-layer","Why teams move the realtime layer",[36,37,38,45,51,57],"ul",{},[39,40,41,44],"li",{},[23,42,43],{},"Explicit pub/sub"," instead of modelling every realtime feature as a change on a stored document.",[39,46,47,50],{},[23,48,49],{},"Database-agnostic",": add realtime to any stack rather than standardising on Firestore.",[39,52,53,56],{},[23,54,55],{},"Blueprint SDKs"," for chat, notifications, dashboards, and tracking.",[39,58,59,62],{},[23,60,61],{},"A coordination layer for AI agents"," on the same platform.",[15,64,66],{"id":65},"concept-map","Concept map",[68,69,70,83],"table",{},[71,72,73],"thead",{},[74,75,76,80],"tr",{},[77,78,79],"th",{},"Firebase",[77,81,82],{},"NoLag",[84,85,86,95,113,131,139],"tbody",{},[74,87,88,92],{},[89,90,91],"td",{},"Realtime Database ref / Firestore collection",[89,93,94],{},"Room + topic",[74,96,97,108],{},[89,98,99,103,104,107],{},[100,101,102],"code",{},"onValue"," / ",[100,105,106],{},"onSnapshot"," listener",[89,109,110],{},[100,111,112],{},"room.on('topic', cb)",[74,114,115,126],{},[89,116,117,103,120,103,123],{},[100,118,119],{},"set",[100,121,122],{},"update",[100,124,125],{},"push",[89,127,128],{},[100,129,130],{},"room.emit('topic', data)",[74,132,133,136],{},[89,134,135],{},"Security rules",[89,137,138],{},"Actors, access tokens, per-topic ACL",[74,140,141,144],{},[89,142,143],{},"Presence via connection state",[89,145,146],{},"Presence (per room)",[15,148,150],{"id":149},"before-firebase-realtime-database","Before: Firebase Realtime Database",[152,153,158],"pre",{"className":154,"code":155,"language":156,"meta":157,"style":157},"language-js shiki shiki-themes github-light github-dark","import { getDatabase, ref, onValue, push } from 'firebase/database'\n\nconst db = getDatabase()\nconst messagesRef = ref(db, 'chat/general/messages')\n\nonValue(messagesRef, (snapshot) => {\n  console.log('Data changed:', snapshot.val())\n})\n\npush(messagesRef, { text: 'Hello!', sender: 'user-123' })\n","js","",[100,159,160,180,187,207,229,234,255,279,285,290],{"__ignoreMap":157},[161,162,165,169,173,176],"span",{"class":163,"line":164},"line",1,[161,166,168],{"class":167},"szBVR","import",[161,170,172],{"class":171},"sVt8B"," { getDatabase, ref, onValue, push } ",[161,174,175],{"class":167},"from",[161,177,179],{"class":178},"sZZnC"," 'firebase/database'\n",[161,181,183],{"class":163,"line":182},2,[161,184,186],{"emptyLinePlaceholder":185},true,"\n",[161,188,190,193,197,200,204],{"class":163,"line":189},3,[161,191,192],{"class":167},"const",[161,194,196],{"class":195},"sj4cs"," db",[161,198,199],{"class":167}," =",[161,201,203],{"class":202},"sScJk"," getDatabase",[161,205,206],{"class":171},"()\n",[161,208,210,212,215,217,220,223,226],{"class":163,"line":209},4,[161,211,192],{"class":167},[161,213,214],{"class":195}," messagesRef",[161,216,199],{"class":167},[161,218,219],{"class":202}," ref",[161,221,222],{"class":171},"(db, ",[161,224,225],{"class":178},"'chat/general/messages'",[161,227,228],{"class":171},")\n",[161,230,232],{"class":163,"line":231},5,[161,233,186],{"emptyLinePlaceholder":185},[161,235,237,239,242,246,249,252],{"class":163,"line":236},6,[161,238,102],{"class":202},[161,240,241],{"class":171},"(messagesRef, (",[161,243,245],{"class":244},"s4XuR","snapshot",[161,247,248],{"class":171},") ",[161,250,251],{"class":167},"=>",[161,253,254],{"class":171}," {\n",[161,256,258,261,264,267,270,273,276],{"class":163,"line":257},7,[161,259,260],{"class":171},"  console.",[161,262,263],{"class":202},"log",[161,265,266],{"class":171},"(",[161,268,269],{"class":178},"'Data changed:'",[161,271,272],{"class":171},", snapshot.",[161,274,275],{"class":202},"val",[161,277,278],{"class":171},"())\n",[161,280,282],{"class":163,"line":281},8,[161,283,284],{"class":171},"})\n",[161,286,288],{"class":163,"line":287},9,[161,289,186],{"emptyLinePlaceholder":185},[161,291,293,295,298,301,304,307],{"class":163,"line":292},10,[161,294,125],{"class":202},[161,296,297],{"class":171},"(messagesRef, { text: ",[161,299,300],{"class":178},"'Hello!'",[161,302,303],{"class":171},", sender: ",[161,305,306],{"class":178},"'user-123'",[161,308,309],{"class":171}," })\n",[15,311,313],{"id":312},"after-nolag","After: NoLag",[152,315,319],{"className":316,"code":317,"language":318,"meta":157,"style":157},"language-ts shiki shiki-themes github-light github-dark","import { NoLag } from '@nolag/js-sdk'\n\nconst client = NoLag('your_access_token')\nawait client.connect()\n\nconst room = client.setApp('chat').setRoom('general')\nroom.subscribe('messages')\n\nroom.on('messages', (data) => {\n  console.log('Message received:', data)\n})\n\nroom.emit('messages', { text: 'Hello!', sender: 'user-123' })\n","ts",[100,320,321,333,337,356,369,373,405,420,424,447,461,466,471],{"__ignoreMap":157},[161,322,323,325,328,330],{"class":163,"line":164},[161,324,168],{"class":167},[161,326,327],{"class":171}," { NoLag } ",[161,329,175],{"class":167},[161,331,332],{"class":178}," '@nolag/js-sdk'\n",[161,334,335],{"class":163,"line":182},[161,336,186],{"emptyLinePlaceholder":185},[161,338,339,341,344,346,349,351,354],{"class":163,"line":189},[161,340,192],{"class":167},[161,342,343],{"class":195}," client",[161,345,199],{"class":167},[161,347,348],{"class":202}," NoLag",[161,350,266],{"class":171},[161,352,353],{"class":178},"'your_access_token'",[161,355,228],{"class":171},[161,357,358,361,364,367],{"class":163,"line":209},[161,359,360],{"class":167},"await",[161,362,363],{"class":171}," client.",[161,365,366],{"class":202},"connect",[161,368,206],{"class":171},[161,370,371],{"class":163,"line":231},[161,372,186],{"emptyLinePlaceholder":185},[161,374,375,377,380,382,384,387,389,392,395,398,400,403],{"class":163,"line":236},[161,376,192],{"class":167},[161,378,379],{"class":195}," room",[161,381,199],{"class":167},[161,383,363],{"class":171},[161,385,386],{"class":202},"setApp",[161,388,266],{"class":171},[161,390,391],{"class":178},"'chat'",[161,393,394],{"class":171},").",[161,396,397],{"class":202},"setRoom",[161,399,266],{"class":171},[161,401,402],{"class":178},"'general'",[161,404,228],{"class":171},[161,406,407,410,413,415,418],{"class":163,"line":257},[161,408,409],{"class":171},"room.",[161,411,412],{"class":202},"subscribe",[161,414,266],{"class":171},[161,416,417],{"class":178},"'messages'",[161,419,228],{"class":171},[161,421,422],{"class":163,"line":281},[161,423,186],{"emptyLinePlaceholder":185},[161,425,426,428,431,433,435,438,441,443,445],{"class":163,"line":287},[161,427,409],{"class":171},[161,429,430],{"class":202},"on",[161,432,266],{"class":171},[161,434,417],{"class":178},[161,436,437],{"class":171},", (",[161,439,440],{"class":244},"data",[161,442,248],{"class":171},[161,444,251],{"class":167},[161,446,254],{"class":171},[161,448,449,451,453,455,458],{"class":163,"line":292},[161,450,260],{"class":171},[161,452,263],{"class":202},[161,454,266],{"class":171},[161,456,457],{"class":178},"'Message received:'",[161,459,460],{"class":171},", data)\n",[161,462,464],{"class":163,"line":463},11,[161,465,284],{"class":171},[161,467,469],{"class":163,"line":468},12,[161,470,186],{"emptyLinePlaceholder":185},[161,472,474,476,479,481,483,486,488,490,492],{"class":163,"line":473},13,[161,475,409],{"class":171},[161,477,478],{"class":202},"emit",[161,480,266],{"class":171},[161,482,417],{"class":178},[161,484,485],{"class":171},", { text: ",[161,487,300],{"class":178},[161,489,303],{"class":171},[161,491,306],{"class":178},[161,493,309],{"class":171},[11,495,496],{},"The key shift is from \"write to a path and listen for changes\" to \"publish an event and subscribe to it.\" You send exactly the message you mean, rather than reshaping your data model so that a write triggers the right listeners.",[15,498,500],{"id":499},"access-control","Access control",[11,502,503,504,507,508,511,512,517],{},"Firebase security rules become ",[23,505,506],{},"per-topic ACL"," in NoLag, tied to a typed ",[23,509,510],{},"actor"," and enforced at the broker rather than written in a rules language. A connection authenticates with an actor token, and browser clients use short-lived JWTs (",[513,514,516],"a",{"href":515},"/docs/client-tokens","client tokens",") your backend signs with a project signing key.",[15,519,521],{"id":520},"next-steps","Next steps",[36,523,524,532,540],{},[39,525,526,527,531],{},"Follow the ",[513,528,530],{"href":529},"/docs/getting-started","5-minute quick start",".",[39,533,534,535,539],{},"See the full ",[513,536,538],{"href":537},"/compare/firebase","NoLag vs Firebase"," comparison.",[39,541,542],{},"If you are keeping a database, use NoLag alongside it for the live layer only.",[544,545,546],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":157,"searchDepth":182,"depth":182,"links":548},[549,550,551,552,553,554,555],{"id":17,"depth":182,"text":18},{"id":33,"depth":182,"text":34},{"id":65,"depth":182,"text":66},{"id":149,"depth":182,"text":150},{"id":312,"depth":182,"text":313},{"id":499,"depth":182,"text":500},{"id":520,"depth":182,"text":521},"Migration Guide","2026-08-01","How to move the realtime layer of a Firebase app to NoLag, when it makes sense, and what to keep. Includes a concept map and before-and-after code.",null,"md",{},"/blog/migrate-from-firebase-to-nolag","7 min read",{"title":5,"description":558},"blog/migrate-from-firebase-to-nolag","ZroLgFe_IFWSfstS-obzl_61VfNpGLwgt61yHYHinYk",1788160341270]