PageSourceSearch

https://vlcn.io/_next/static/chunks/pages/docs-03c3a5db779139a4.js

js vlcn.io collected 2026-10-03 20:31:59 UTC 17,030 bytes, 1 lines download raw bytes

1(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[3172],{19815:function(e,t,i){(window.__NEXT_P=window.__NEXT_P||[]).push(["/docs",function(){return i(60161)}])},38107:function(e,t,i){"use strict";var r=i(11527),a=i(65705);t.Z={logo:(0,r.jsx)("img",{src:"/logo.png",style:{height:48}}),project:{link:"https://github.com/vlcn-io/cr-sqlite"},darkMode:!1,nextThemes:{defaultTheme:"light",forcedTheme:"light"},chat:{link:"https://discord.gg/AtdVY6zDW3"},docsRepositoryBase:"https://github.com/vlcn-io/docs/tree/main",footer:{text:(0,r.jsxs)("span",{children:["MIT ",new Date().getFullYear()," \xa9"," ",(0,r.jsx)("a",{href:"https://vlcn.io",target:"_blank",children:"One Law LLC"})]})},head:()=>{let{frontMatter:e}=(0,a.ZR)();return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),(0,r.jsx)("meta",{name:"keywords",content:"software, crdts, crrs, sqlite, conflict-free"}),(0,r.jsx)("meta",{name:"twitter:image",content:e.image||"https://vlcn.io/assets/hero.png"}),(0,r.jsx)("meta",{name:"copyright",content:"\xa9 2022 One Law LLC"})]})},useNextSeoProps(){let{frontMatter:e}=(0,a.ZR)();return{additionalLinkTags:[{href:"/favicon-32x32.png",rel:"icon",sizes:"32x32",type:"image/png"},{href:"/favicon-16x16.png",rel:"icon",sizes:"16x16",type:"image/png"}],additionalMetaTags:[{content:"en",httpEquiv:"Content-Language"},{content:"vlcn.io",name:"apple-mobile-web-app-title"}
1,{content:"#fff",name:"msapplication-TileColor"}],description:e.description||"Distributed State, Simplified",openGraph:{description:e.description||"Distributed State, Simplified",siteName:"vlcn.io",images:[{url:e.image||"https://vlcn.io/assets/hero.png"}]},titleTemplate:"%s – vlcn.io",twitter:{cardType:"summary_large_image",site:"@vlcnio"}}}}},60161:function(e,t,i){"use strict";i.r(t),i.d(t,{__toc:function(){return d}});var r=i(11527),a=i(98682),n=i(65705),o=i(38107);i(13762);var s=i(36929);let d=[{depth:2,value:"How it Works",id:"how-it-works"}];function c(e){let t=Object.assign({h1:"h1",p:"p",ol:"ol",li:"li",a:"a",h2:"h2",strong:"strong",blockquote:"blockquote"},(0,s.a)(),e.components);return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{children:"Background"}),"\n",(0,r.jsx)(t.p,{children:"We want applications:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsx)(t.li,{children:"That don't break on network hiccups"}),"\n",(0,r.jsx)(t.li,{children:"That can sync across devices"}),"\n",(0,r.jsx)(t.li,{children:"Allow users to collaborate"}),"\n",(0,r.jsx)(t.li,{children:"Allow users to view and edit their data while offline"}),"\n",(0,r.jsx)(t.li,{children:"Have instant interactions"}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["Vulcan is ",(0,r.jsx)(t.a,{href:"/docs/cr-sqlite/intro",children:"a database extension"})," and ",(0,r.jsx)(t.a,{href:"/docs/cr-sqlite/js/wasm",children:"set of platform SDKs"})," to allow you to create these kinds of applications without being a distributed systems expert."]}),"\n",(0,r.jsx)(t.p,{children:"While Vulcan can be run in a traditional client-server setup, it also supports P2P replication and syncing. In other words, a truly serverless setup. One where each device on the network is a peer and there is no server to serve as a central point of failure."}),"\n",(0,r.jsx)(t.h2,{id:"how-it-works",children:"How it Works"}),"\n",(0,r.jsxs)(t.p,{children:["The base of everything is ",(0,r.jsx)(t.a,{href:"/docs/cr-sqlite/intro",children:"cr-sqlite"}),". An extension to SQLite to enable it to merge in changes from other databases and automatically resolve merge conflicts."]}),"\n",(0,r.jsx)(t.p,{children:"This means that users can write to their local database and merge those changes with other users or devices who may have also made independent changes to their local database. Merging can happen in real time or lazily as network conditions allow."}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"In technical terms:"})," cr-sqlite adds ",(0,r.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Multi-master_replication",children:"multi-master replication"})," and ",(0,r.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Network_partition",children:"partition tolerance"})," to SQLite via ",(0,r.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type",children:"conflict free replicated data types"})," (CRDTs)."]}),"\n",(0,r.jsxs)(t.blockquote,{children:["\n",(0,r.jsx)(t.p,{children:"It's like git, for your data."}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:'This capability is the foundation of the 5 features listed above as all of these involve a "merging of edits" problem.'}),"\n",(0,r.jsxs)(t.p,{children:["For those that want a better understanding of the theory behind Vulcan & cr-sqlite, see\nthe ",(0,r.jsx)(t.a,{href:"/docs/appendix/causal-consistency",children:"deep dive section"}),". Otherwise, continue\nto the getting started section."]})]})}let l={MDXContent:function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},{wrapper:t}=Object.assign({},(0,s.a)(),e.components);return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)},pageOpts:{filePath:"pages/docs/index.mdx",route:"/docs",pageMap:[{kind:"Meta",data:{index:{display:"hidden",type:"page",theme:{layout:"raw",breadcrumb:!1,footer:!1,navbar:!1,sidebar:!1,toc:!0,pagination:!1},title:"Vulcan - state, simplified"},docs:{type:"page",title:"Docs"},examples:{type:"page",title:"Examples"},blog:{title:"Blog",type:"page"},about:{type:"page",display:"hidden",title:"About"}}},{kind:"MdxPage",name:"about",route:"/about"},{kind:"Folder",name:"blog",route:"/blog",children:[{kind:"Meta",data:{"*":{display:"hidden",theme:{toc:!1,sidebar:!1,pagination:!1,typesetting:"article"}},"how-crsqlite-transactions-work-tomorrow":"How CR-SQLite Transactions Work Tomorrow","how-crsqlite-transactions-work-today":"How CR-SQLite Transactions Work Today","the-march-to-reactivity":{title:"The March to Reactivity"},"how-crsqlite-works-tomorrow":"How CR-SQLite Works Tomorrow","crdt-substrate":"A Framework for Convergence","intro-to-crdts":{title:"A Gentle Introduction to CRDTs"},"lww-vs-dag":{title:"LWW vs DAG",theme:{layout:"full",breadcrumb:!1,footer:!0,sidebar:!1,toc:!1,pagination:!1,typesetting:"article"}},"fractional-indexing":{title:"Fractional Indexing"},"recursive-ordering":{title:"Recursive Ordering"},"recursive-ordering-in-sqlite":{title:"Recursive Ordering in Sqlite"},"bring-your-own-crdt":{theme:{layout:"full",breadcrumb:!1,footer:!0,sidebar:!1,toc:!1,pagination:!1,typesetting:"article"},display:"hidden",title:"Bring Your Own Crdt"},"distributed-recursive-ordering":{title:"Distributed Recursive Ordering"},"a-million-rows-with-differential-dataflow":"A Million Rows in React with Differential Dataflow","differential-dataflow":"Differential Dataflow For Mere Mortals","sqlite-isnt-it":"Sqlite Isnt It",reflections:"Reflections","libsql-gdoc":"Libsql Gdoc","making-async-apis-synchronous":"Making Async Apis Synchronous",roadmap:"Roadmap","simpler-materialize-with-a-query-database":"Simpler Materialize with a Query Database"}},{kind:"MdxPage",name:"a-million-rows-with-differential-dataflow",route:"/blog/a-million-rows-with-differential-dataflow",frontMatter:{title:"A Million Rows in React with Differential Dataflow",description:"Incremental Computation",date:"October 19th, 2023"}},{kind:"MdxPage",name:"bring-your-own-crdt",route:"/blog/bring-your-own-crdt",frontMatter:{draft:!0}},{kind:"MdxPage",name:"crdt-substrate",route:"/blog/crdt-substrate",frontMatter:{image:"/blog/crdt-substrate/told-you.jpg",title:"A Framework for Convergence: Creating CRDTs Without Specialized Knowledge",description:"What if I told you anyone can create a new CRDT? That you can do this without any special knowledge of distributed systems?",date:"June 1st, 2023"}},{kind:"MdxPage",name:"differential-dataflow",route:"/blog/differential-dataflow",frontMatter:{title:"Differential Dataflow For Mere Mortals",description:"Demistifying Differential Dataflow",date:"October 16th, 2023"}},{kind:"MdxPage",name:"distributed-recursive-ordering",route:"/blog/distributed-recursive-ordering",frontMatter:{draft:!0}},{kind:"MdxPage",name:"fractional-indexing",route:"/blog/fractional-indexing",frontMatter:{description:"To enable user provided ordering of rows, most people reach for a fractional index. They're great given they let you change the position of one row without modifying any other rows. Fractional indices have a number of gotchas, however.",date:"January 26, 2023"}},{kind:"MdxPage",name:"how-crsqlite-transactions-work-today",route:"/blog/how-crsqlite-transactions-work-today",frontMatter:{description:"An overview of the design decisions for the current implementation of cr-sqlite and their impact on transaction guarantees",date:"June 6, 2023"}},{kind:"MdxPage",name:"how-crsqlite-transactions-work-tomorrow",route:"/blog/how-crsqlite-transactions-work-tomorrow",frontMatter:{description:"Future improvements for transactional guarantees",date:"June 14, 2023"}},{kind:"MdxPage",name:"intro-to-crdts",route:"/blog/intro-to-crdts",frontMatter:{title:"A Gentle Introduction to CRDTs",description:"Conflict Free Replicated Data types (CRDTs) can be tricky. You may spend months reading papers and implementing different algorithms before they finally click and become simple. That or they'll seem simple out of the gate and you'll be missing a bunch of nuance.",date:"April 1, 2023"}},{kind:"MdxPage",name:"libsql-gdoc",route:"/blog/libsql-gdoc",frontMatter:{draft:!0}},{kind:"MdxPage",name:"lww-vs-dag",route:"/blog/lww-vs-dag",frontMatter:{date:"February 17, 2023",description:"Event sourcing is a fairly common design pattern for deriving application state from a history of events. But is it possible to turn an event log into a CRDT? To allow nodes to append events to the log, without coordinating with other nodes? Can we merge all these copies of the log, proces them, and arrive at the same application state across all nodes?"}},{kind:"MdxPage",name:"making-async-apis-synchronous",route:"/blog/making-async-apis-synchronous",frontMatter:{draft:!0}},{kind:"MdxPage",name:"recursive-ordering-in-sqlite",route:"/blog/recursive-ordering-in-sqlite",frontMatter:{description:"Sorting by recursive relationships efficie
1ntly in SQL",date:"December 20, 2022"}},{kind:"MdxPage",name:"recursive-ordering",route:"/blog/recursive-ordering",frontMatter:{description:"Keeping things sorted without interleaving edits.",date:"December 20, 2022"}},{kind:"MdxPage",name:"reflections",route:"/blog/reflections",frontMatter:{description:"Local-First, Collaboration, Multiplayer, Latency, The Cloud, The Edge",date:"December 12, 2023",draft:!0}},{kind:"MdxPage",name:"roadmap",route:"/blog/roadmap",frontMatter:{draft:!0}},{kind:"MdxPage",name:"simpler-materialize-with-a-query-database",route:"/blog/simpler-materialize-with-a-query-database",frontMatter:{draft:!0}},{kind:"MdxPage",name:"sqlite-isnt-it",route:"/blog/sqlite-isnt-it",frontMatter:{description:"SQLite isn't it",date:"December 18, 2023",draft:!0}},{kind:"MdxPage",name:"the-march-to-reactivity",route:"/blog/the-march-to-reactivity",frontMatter:{date:"June 5, 2023",description:"The request-response pattern isn't optimal for the types of applications we'd like to build today. If you want your application to update as soon as information is available, it is much easier for that information to be pushed to you incrementally than for you to have to go request it."}}]},{kind:"MdxPage",name:"blog",route:"/blog",frontMatter:{description:"The latest updates, releases and explorations by the Vulcan team.",type:"posts"}},{kind:"Folder",name:"docs",route:"/docs",children:[{kind:"Meta",data:{index:{title:"Background"},"getting-started":{title:"Getting Started"},"cr-sqlite":"CR-SQLite",appendix:"Appendix"}},{kind:"Folder",name:"appendix",route:"/docs/appendix",children:[{kind:"Meta",data:{crr:"CRR","causal-consistency":"Causal Consistency",languages:"Languages"}},{kind:"MdxPage",name:"causal-consistency",route:"/docs/appendix/causal-consistency"},{kind:"MdxPage",name:"crr",route:"/docs/appendix/crr"},{kind:"MdxPage",name:"languages",route:"/docs/appendix/languages"}]},{kind:"Folder",name:"cr-sqlite",route:"/docs/cr-sqlite",children:[{kind:"Meta",data:{intro:"Intro",installation:"Installation",quickstart:"Quickstart",js:{title:"JS & The Browser"},"api-methods":"API Methods",migrations:{title:"Migrations"},crdts:"CRDTs",networking:"Networking & Syncing",constraints:"Constraints","custom-syntax":"Custom Syntax"}},{kind:"Folder",name:"api-methods",route:"/docs/cr-sqlite/api-methods",children:[{kind:"Meta",data:{crsql_as_crr:"crsql_as_crr",crsql_finalize:"crsql_finalize",crsql_changes:"crsql_changes",crsql_begin_alter:"crsql_begin_alter",crsql_commit_alter:"crsql_commit_alter",crsql_tracked_peers:{title:"crsql_tracked_peers"},crsql_db_version:"crsql_db_version",crsql_site_id:"crsql_site_id",crsql_fract_as_ordered:"crsql_fract_as_ordered",crsql_master:"crsql_master","sqlite-apis":"SQLite APIs"}},{kind:"MdxPage",name:"crsql_as_crr",route:"/docs/cr-sqlite/api-methods/crsql_as_crr"},{kind:"MdxPage",name:"crsql_begin_alter",route:"/docs/cr-sqlite/api-methods/crsql_begin_alter"},{kind:"MdxPage",name:"crsql_changes",route:"/docs/cr-sqlite/api-methods/crsql_changes"},{kind:"MdxPage",name:"crsql_commit_alter",route:"/docs/cr-sqlite/api-methods/crsql_commit_alter"},{kind:"MdxPage",name:"crsql_db_version",route:"/docs/cr-sqlite/api-methods/crsql_db_version"},{kind:"MdxPage",name:"crsql_finalize",route:"/docs/cr-sqlite/api-methods/crsql_finalize"},{kind:"MdxPage",name:"crsql_fract_as_ordered",route:"/docs/cr-sqlite/api-methods/crsql_fract_as_ordered"},{kind:"MdxPage",name:"crsql_master",route:"/docs/cr-sqlite/api-methods/crsql_master"},{kind:"MdxPage",name:"crsql_site_id",route:"/docs/cr-sqlite/api-methods/crsql_site_id"},{kind:"MdxPage",name:"crsql_tracked_peers",route:"/docs/cr-sqlite/api-methods/crsql_tracked_peers"},{kind:"MdxPage",name:"sqlite-apis",route:"/docs/cr-sqlite/api-methods/sqlite-apis"}]},{kind:"MdxPage",name:"constraints",route:"/docs/cr-sqlite/constraints"},{kind:"Folder",name:"crdts",route:"/docs/cr-sqlite/crdts",children:[{kind:"Meta",data:{about:{title:"About"},"table-crdts":"Table CRDTs","column-crdts":"Column CRDTs","sequence-crdts":"Sequence CRDTs"}},{kind:"MdxPage",name:"about",route:"/docs/cr-sqlite/crdts/about"},{kind:"MdxPage",name:"column-crdts",route:"/docs/cr-sqlite/crdts/column-crdts"},{kind:"MdxPage",name:"sequence-crdts",route:"/docs/cr-sqlite/crdts/sequence-crdts"},{kind:"MdxPage",name:"table-crdts",route:"/docs/cr-sqlite/crdts/table-crdts"}]},{kind:"MdxPage",name:"custom-syntax",route:"/docs/cr-sqlite/custom-syntax"},{kind:"MdxPage",name:"installation",route:"/docs/cr-sqlite/installation"},{kind:"MdxPage",name:"intro",route:"/docs/cr-sqlite/intro"},{kind:"Folder",name:"js",route:"/docs/cr-sqlite/js",children:[{kind:"Meta",data:{"first-app":"Your First App",react:"ReactJS",wasm:"WASM & Browser APIs",persistence:"Browser Persistence",networking:{title:"Networking"},reactivity:"Reactivity",nodejs:"NodeJS","example-apps":{title:"Example Apps"}}},{kind:"MdxPage",name:"example-apps",route:"/docs/cr-sqlite/js/example-apps"},{kind:"MdxPage",name:"first-app",route:"/docs/cr-sqlite/js/first-app"},{kind:"MdxPage",name:"networking",route:"/docs/cr-sqlite/js/networking"},{kind:"MdxPage",name:"nodejs",route:"/docs/cr-sqlite/js/nodejs"},{kind:"MdxPage",name:"persistence",route:"/docs/cr-sqlite/js/persistence"},{kind:"MdxPage",name:"react",route:"/docs/cr-sqlite/js/react"},{kind:"MdxPage",name:"reactivity",route:"/docs/cr-sqlite/js/reactivity"},{kind:"MdxPage",name:"wasm",route:"/docs/cr-sqlite/js/wasm"}]},{kind:"MdxPage",name:"migrations",route:"/docs/cr-sqlite/migrations"},{kind:"Folder",name:"networking",route:"/docs/cr-sqlite/networking",children:[{kind:"Meta",data:{background:{title:"Backgroun
1d"},"whole-crr-sync":"Whole CRR Sync","partial-crr-sync":"Partial CRR Sync",implementations:"Implementations"}},{kind:"MdxPage",name:"background",route:"/docs/cr-sqlite/networking/background"},{kind:"MdxPage",name:"implementations",route:"/docs/cr-sqlite/networking/implementations"},{kind:"MdxPage",name:"partial-crr-sync",route:"/docs/cr-sqlite/networking/partial-crr-sync"},{kind:"MdxPage",name:"whole-crr-sync",route:"/docs/cr-sqlite/networking/whole-crr-sync"}]},{kind:"MdxPage",name:"quickstart",route:"/docs/cr-sqlite/quickstart"}]},{kind:"MdxPage",name:"getting-started",route:"/docs/getting-started"},{kind:"MdxPage",name:"index",route:"/docs"}]},{kind:"MdxPage",name:"examples",route:"/examples"},{kind:"MdxPage",name:"index",route:"/",frontMatter:{title:"Vulcan - state, simplified",description:"Make collaborative, multiplayer or local-first applications",image:"https://vlcn.io/_next/image?url=%2Fhero.png&w=1200&q=75"}}],flexsearch:{codeblocks:!0},title:"Background",headings:d},pageNextRoute:"/docs",nextraLayout:n.ZP,themeConfig:o.Z};t.default=(0,a.j)(l)}},function(e){e.O(0,[6785,9774,2888,179],function(){return e(e.s=19815)}),_N_E=e.O()}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.