forked from pubkey/rxdb
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathoffline-first.html
81 lines (77 loc) · 33.6 KB
/
offline-first.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-current docs-doc-page docs-doc-id-offline-first" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v3.0.1">
<title data-rh="true">Local First / Offline First | RxDB - JavaScript Database</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://rxdb.info/img/rxdb_social_card.png"><meta data-rh="true" name="twitter:image" content="https://rxdb.info/img/rxdb_social_card.png"><meta data-rh="true" property="og:url" content="https://rxdb.info/offline-first.html"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Local First / Offline First | RxDB - JavaScript Database"><meta data-rh="true" name="description" content="Local-First software stores data on client devices for seamless offline and online functionality, enhancing user experience and efficiency."><meta data-rh="true" property="og:description" content="Local-First software stores data on client devices for seamless offline and online functionality, enhancing user experience and efficiency."><link data-rh="true" rel="icon" href="/img/favicon.ico"><link data-rh="true" rel="canonical" href="https://rxdb.info/offline-first.html"><link data-rh="true" rel="alternate" href="https://rxdb.info/offline-first.html" hreflang="en"><link data-rh="true" rel="alternate" href="https://rxdb.info/offline-first.html" hreflang="x-default"><link rel="preconnect" href="https://www.google-analytics.com">
<link rel="preconnect" href="https://www.googletagmanager.com">
<script async src="https://www.googletagmanager.com/gtag/js?id=G-62D63SY3S0"></script>
<script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-62D63SY3S0",{})</script>
<link rel="preconnect" href="https://www.googletagmanager.com">
<script>window.dataLayer=window.dataLayer||[]</script>
<script>!function(e,t,a,n,g){e[n]=e[n]||[],e[n].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var m=t.getElementsByTagName(a)[0],r=t.createElement(a);r.async=!0,r.src="https://www.googletagmanager.com/gtm.js?id=GTM-PL63TR5",m.parentNode.insertBefore(r,m)}(window,document,"script","dataLayer")</script>
<script id="Cookiebot" src="https://consent.cookiebot.com/uc.js?cbid=c429ebbd-6e92-4150-b700-ca186e06bc7c" data-cbid="c429ebbd-6e92-4150-b700-ca186e06bc7c" data-blockingmode="auto" async></script>
<script src="/js/analytics.js" async></script><link rel="stylesheet" href="/assets/css/styles.0bd0feed.css">
<script src="/assets/js/runtime~main.ffbf8b01.js" defer="defer"></script>
<script src="/assets/js/main.3546531e.js" defer="defer"></script>
</head>
<body class="navigation-with-keyboard">
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-PL63TR5" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return localStorage.getItem("theme")}catch(t){}}();t(null!==e?e:"dark")}(),function(){try{const c=new URLSearchParams(window.location.search).entries();for(var[t,e]of c)if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id="__docusaurus"><div role="region" aria-label="Skip to main content"><a class="skipToContent_fXgn" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/"><div class="navbar__logo"><img src="/files/logo/logo.svg" alt="RxDB Logo" class="themedComponent_mlkZ themedComponent--light_NVdE"><img src="/files/logo/logo.svg" alt="RxDB Logo" class="themedComponent_mlkZ themedComponent--dark_xIcU"></div><b class="navbar__title text--truncate">RxDB</b></a></div><div class="navbar__items navbar__items--right"><a class="navbar__item navbar__link" href="/quickstart.html">Docs</a><a class="navbar__item navbar__link" target="_blank" href="/code">Code</a><a class="navbar__item navbar__link" href="/premium">Pricing</a><a class="navbar__item navbar__link" href="/consulting">Consulting</a><a class="navbar__item navbar__link" target="_blank" href="/chat">Chat</a><div class="navbarSearchContainer_Bca1"><div class="navbar__search"><span aria-label="expand searchbar" role="button" class="search-icon" tabindex="0"></span><input id="search_input_react" type="search" placeholder="Loading..." aria-label="Search" class="navbar__search-input search-bar" disabled=""></div></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="__docusaurus_skipToContent_fallback" class="main-wrapper mainWrapper_z2l0"><div class="docsWrapper_hBAB"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_sjWU" type="button"></button><div class="docRoot_UBD9"><aside class="theme-doc-sidebar-container docSidebarContainer_YfHR"><div class="sidebarViewport_aRkj"><div class="sidebar_njMd"><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_SIkG"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/quickstart.html">🚀 Quickstart</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/install.html">Installation</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/dev-mode.html">Dev-Mode Plugin</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/rx-database.html">RxDatabase</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/rx-schema.html">RxSchema</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/rx-collection.html">RxCollection</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/rx-document.html">RxDocument</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/rx-query.html">RxQuery</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/rx-attachment.html">Attachments</a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/rx-storage.html">💾 RxStorage</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/replication.html">🔄 Replication</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/rx-server.html">Server</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/migration-schema.html">Migration</a></div></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/schema-validation.html">Schema Validation</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/reactivity.html">Signals & Custom Reactivity</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/rx-state.html">RxState</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/rx-local-document.html">Local Documents</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/encryption.html">Encryption</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/key-compression.html">Key Compression</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/leader-election.html">Leader Election</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/cleanup.html">Cleanup</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/backup.html">Backup</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/transactions-conflicts-revisions.html">Transactions, Conflicts and Revisions</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/middleware.html">Middleware</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/query-cache.html">Query Cache</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/crdt.html">CRDT - Conflict-free replicated data type Database</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/population.html">Population</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/orm.html">ORM</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/query-optimizer.html">Query Optimizer 👑</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/logger.html">Logger 👑</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/plugins.html">Plugins</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/nosql-performance-tips.html">RxDB NoSQL Performance Tips</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/third-party-plugins.html">Third Party Plugins</a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/tutorials/typescript.html">Tutorials</a></div></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/questions-answers.html">Questions and Answers</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/contribution.html">Contribute to RxDB</a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/releases/15.0.0.html">🆕 Releases</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret menu__link--active" aria-expanded="true" href="/offline-first.html">Articles</a></div><ul style="display:block;overflow:visible;height:auto" class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/offline-first.html">Local First / Offline First</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/downsides-of-offline-first.html">Downsides of Local First / Offline First</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/slow-indexeddb.html">Slow IndexedDB</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/why-nosql.html">Why NOSQL</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/react-native-database.html">React Native Database</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/alternatives.html">Alternatives for realtime offline-first JavaScript applications and local databases</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/angular-database.html">RxDB as a Database in an Angular Application</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/browser-database.html">The benefits of Browser Databases and RxDB</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/browser-storage.html">Browser Storage - RxDB as a Database for Browsers</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/data-base.html">RxDB as a data base - Empowering Web Applications with Reactive Data Handling</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/embedded-database.html">Using RxDB as an Embedded Database</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/flutter-database.html">RxDB as a Database in a Flutter Application</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/frontend-database.html">RxDB JavaScript Frontend Database - Efficient Data Storage in Frontend Applications</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/in-memory-nosql-database.html">RxDB as In-memory NoSQL Database - Empowering Real-Time Applications</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/ionic-database.html">Ionic Storage - RxDB as database for hybrid apps</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/json-database.html">RxDB - JSON Database for JavaScript</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/websockets-sse-polling-webrtc-webtransport.html">WebSockets vs Server-Sent-Events vs Long-Polling vs WebRTC vs WebTransport</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/localstorage.html">Using localStorage in Modern Applications - A Comprehensive Guide</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/mobile-database.html">Mobile Database - RxDB as Database for Mobile Applications</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/progressive-web-app-database.html">RxDB as a Database for Progressive Web Apps (PWA)</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/react-database.html">RxDB as a Database for React Applications</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/articles/realtime-database.html">What is a realtime database?</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/capacitor-database.html">Capacitor Database - SQLite, RxDB and others</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/electron-database.html">Electron Database - Storage adapters for SQLite, Filesystem and In-Memory</a></li></ul></li></ul></nav></div></div></aside><main class="docMainContainer_TBSr"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_VOVn"><div class="docItemContainer_Djhp"><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_Z_bl" aria-label="Breadcrumbs"><ul class="breadcrumbs" itemscope="" itemtype="https://schema.org/BreadcrumbList"><li class="breadcrumbs__item"><a aria-label="Home page" class="breadcrumbs__link" href="/"><svg viewBox="0 0 24 24" class="breadcrumbHomeIcon_YNFT"><path d="M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z" fill="currentColor"></path></svg></a></li><li class="breadcrumbs__item"><span class="breadcrumbs__link">Articles</span><meta itemprop="position" content="1"></li><li itemscope="" itemprop="itemListElement" itemtype="https://schema.org/ListItem" class="breadcrumbs__item breadcrumbs__item--active"><span class="breadcrumbs__link" itemprop="name">Local First / Offline First</span><meta itemprop="position" content="2"></li></ul></nav><div class="tocCollapsible_ETCw theme-doc-toc-mobile tocMobile_ITEo"><button type="button" class="clean-btn tocCollapsibleButton_TO0P">On this page</button></div><div class="theme-doc-markdown markdown"><h1>Local First / Offline First</h1>
<p>Local-First (aka offline first) is a software paradigm where the software stores data locally at the clients device and must work as well offline as it does online.
To implement this, you have to store data at the client side, so that your application can still access it when the internet goes away.
This can be either done with complex caching strategies, or by using an local-first, offline database (like <a href="https://rxdb.info" target="_blank" rel="noopener noreferrer">RxDB</a>) that stores the data inside of a local database like IndexedDB and replicates it from and to the backend in the background. This makes the local database, not the server, the gateway for all persistent changes in application state.</p>
<blockquote>
<p><strong>Offline first is not about having no internet connection</strong></p>
</blockquote>
<p>While in the past, internet connection was an unstable, things are changing especially for mobile devices.
Mobile networks become better and having no internet becomes less common even in remote locations.
So if we did not care about offline first applications in the past, why should we even care now?
In the following I will point out why offline first applications are better, not because they support offline usage, but because of other reasons.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ux-is-better-without-loading-spinners">UX is better without loading spinners<a href="#ux-is-better-without-loading-spinners" class="hash-link" aria-label="Direct link to UX is better without loading spinners" title="Direct link to UX is better without loading spinners"></a></h2>
<p>In 'normal' web applications, most user interactions like fetching, saving or deleting data, correspond to a request to the backend server. This means that each of these interactions require the user to await the unknown latency to and from a remote server while looking at a loading spinner.
In offline-first apps, the operations go directly against the local storage which happens almost instantly. There is no perceptible loading time and so it is not even necessary to implement a loading spinner at all. As soon as the user clicks, the UI represents the new state as if it was already changed in the backend.</p>
<p align="center"><img src="./files/loading-spinner-not-needed.gif" alt="loading spinner not needed" width="300"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="multi-tab-usage-just-works">Multi-tab usage just works<a href="#multi-tab-usage-just-works" class="hash-link" aria-label="Direct link to Multi-tab usage just works" title="Direct link to Multi-tab usage just works"></a></h2>
<p>Many, even big websites like amazon, reddit and stack overflow do not handle multi tab usage correctly. When a user has multiple tabs of the website open and does a login on one of these tabs, the state does not change on the other tabs.
On offline first applications, there is always exactly one state of the data across all tabs. Offline first databases (like RxDB) store the data inside of IndexedDb and <strong>share the state</strong> between all tabs of the same origin.</p>
<p align="center"><img src="./files/multiwindow.gif" alt="RxDB multi tab" width="450"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="latency-is-more-important-than-bandwidth">Latency is more important than bandwidth<a href="#latency-is-more-important-than-bandwidth" class="hash-link" aria-label="Direct link to Latency is more important than bandwidth" title="Direct link to Latency is more important than bandwidth"></a></h2>
<p>In the past, often the bandwidth was the limiting factor on determining the loading time of an application.
But while bandwidth has improved over the years, latency became the limiting factor.
You can always increase the bandwidth by setting up more cables or sending more Starlink satellites to space.
But reducing the latency is not so easy. It is defined by the physical properties of the transfer medium, the speed of light and the distance to the server. All of these three are hard to optimize.</p>
<p>Offline first application benefit from that because sending the initial state to the client can be done much faster with more bandwidth. And once the data is there, we do no longer have to care about the latency to the backend server.</p>
<p align="center"><img src="./files/latency-london-san-franzisco.png" alt="latency london san franzisco" width="300"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="realtime-comes-for-free">Realtime comes for free<a href="#realtime-comes-for-free" class="hash-link" aria-label="Direct link to Realtime comes for free" title="Direct link to Realtime comes for free"></a></h2>
<p>Most websites lie to their users. They do not lie because they display wrong data, but because they display <strong>old data</strong> that was loaded from the backend at the time the user opened the site.
To overcome this, you could build a realtime website where you create a websocket that streams updates from the backend to the client. This means work. Your client needs to tell the server which page is currently opened and which updates the client is interested to. Then the server can push updates over the websocket and you can update the UI accordingly.</p>
<p>With offline first applications, you already have a realtime replication with the backend. Most offline first databases provide some concept of changestream or data subscriptions and with <a href="https://github.com/pubkey/rxdb" target="_blank" rel="noopener noreferrer">RxDB</a> you can even directly subscribe to query results or single fields of documents. This makes it easy to have an always updated UI whenever data on the backend changes.</p>
<p align="center"><img src="./files/animations/realtime.gif" alt="realtime ui updates" width="700"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="scales-with-data-size-not-with-the-amount-of-user-interaction">Scales with data size, not with the amount of user interaction<a href="#scales-with-data-size-not-with-the-amount-of-user-interaction" class="hash-link" aria-label="Direct link to Scales with data size, not with the amount of user interaction" title="Direct link to Scales with data size, not with the amount of user interaction"></a></h2>
<p>On normal applications, each user interaction can result in multiple requests to the backend server which increase its load.
The more users interact with your application, the more backend resources you have to provide.</p>
<p>Offline first applications do not scale up with the amount of user actions but instead they scale up with the amount of data.
Once that data is transferred to the client, the user can do as many interactions with it as required without connecting to the server.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="modern-apps-have-longer-runtimes">Modern apps have longer runtimes<a href="#modern-apps-have-longer-runtimes" class="hash-link" aria-label="Direct link to Modern apps have longer runtimes" title="Direct link to Modern apps have longer runtimes"></a></h2>
<p>In the past you used websites only for a short time. You open it, perform some action and then close it again. This made the first load time the important metric when evaluating page speed.
Today web applications have changed and with it the way we use them. Single page applications are opened once and then used over the whole day. Chat apps, email clients, PWAs and hybrid apps. All of these were made to have long runtimes.
This makes the time for user interactions more important than the initial loading time. Offline first applications benefit from that because there is often no loading time on user actions while loading the initial state to the client is not that relevant.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="you-might-not-need-rest">You might not need REST<a href="#you-might-not-need-rest" class="hash-link" aria-label="Direct link to You might not need REST" title="Direct link to You might not need REST"></a></h2>
<p>On normal web applications, you make different requests for each kind of data interaction.
For that you have to define a swagger route, implement a route handler on the backend and create some client code to send or fetch data from that route. The more complex your application becomes, the more REST routes you have to maintain and implement.</p>
<p>With offline first apps, you have a way to hack around all this cumbersome work. You just replicate the whole state from the server to the client. The replication does not only run once, you have a <strong>realtime replication</strong> and all changes at one side are automatically there on the other side. On the client, you can access every piece of state with a simple database query.
While this of course only works for amounts of data that the client can load and store, it makes implementing prototypes and simple apps much faster.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="you-might-not-need-redux">You might not need Redux<a href="#you-might-not-need-redux" class="hash-link" aria-label="Direct link to You might not need Redux" title="Direct link to You might not need Redux"></a></h2>
<p>Data is hard, especially for UI applications where many things can happen at the same time.
The user is clicking around. Stuff is loaded from the server. All of these things interact with the global state of the app.
To manage this complexity it is common to use state management libraries like Redux or MobX. With them, you write all this lasagna code to wrap the mutation of data and to make the UI react to all these changes.</p>
<p>On offline first apps, your global state is already there in a single place stored inside of the local database.
You do not have to care whether this data came from the UI, another tab, the backend or another device of the same user. You can just make writes to the database and fetch data out of it.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="follow-up">Follow up<a href="#follow-up" class="hash-link" aria-label="Direct link to Follow up" title="Direct link to Follow up"></a></h2>
<ul>
<li>Learn how to store and query data with RxDB in the <a href="/quickstart.html">RxDB Quickstart</a></li>
<li><a href="/downsides-of-offline-first.html">Downsides of Offline First</a></li>
</ul></div></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/releases/8.0.0.html"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">RxDB 8.0.0</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/downsides-of-offline-first.html"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Downsides of Local First / Offline First</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#ux-is-better-without-loading-spinners" class="table-of-contents__link toc-highlight">UX is better without loading spinners</a></li><li><a href="#multi-tab-usage-just-works" class="table-of-contents__link toc-highlight">Multi-tab usage just works</a></li><li><a href="#latency-is-more-important-than-bandwidth" class="table-of-contents__link toc-highlight">Latency is more important than bandwidth</a></li><li><a href="#realtime-comes-for-free" class="table-of-contents__link toc-highlight">Realtime comes for free</a></li><li><a href="#scales-with-data-size-not-with-the-amount-of-user-interaction" class="table-of-contents__link toc-highlight">Scales with data size, not with the amount of user interaction</a></li><li><a href="#modern-apps-have-longer-runtimes" class="table-of-contents__link toc-highlight">Modern apps have longer runtimes</a></li><li><a href="#you-might-not-need-rest" class="table-of-contents__link toc-highlight">You might not need REST</a></li><li><a href="#you-might-not-need-redux" class="table-of-contents__link toc-highlight">You might not need Redux</a></li><li><a href="#follow-up" class="table-of-contents__link toc-highlight">Follow up</a></li></ul></div></div></div></div></main></div></div></div><div class="block footer"><div class="footer-block"><div class="footer-links"><span><a variant="text" href="/" class="footer-logo-button"><img src="/files/logo/logo.svg" alt="RxDB"><div>RxDB</div></a><div class="footer-community-links"><a variant="text" href="/chat" target="_blank"><img src="/img/community-links/discord-logo.svg" alt="logo"></a><a variant="text" href="/code" target="_blank"><img src="/img/community-links/github-logo.svg" alt="logo"></a><a variant="text" href="https://twitter.com/intent/user?screen_name=rxdbjs" target="_blank"><img src="/img/community-links/x-logo.svg" alt="logo"></a><a variant="text" href="https://www.linkedin.com/company/rxdb" target="_blank"><img src="/img/community-links/linkedin-logo.svg" alt="logo"></a><a variant="text" href="https://stackoverflow.com/questions/tagged/rxdb" target="_blank"><img src="/img/community-links/stack-overflow-logo.svg" alt="logo"></a></div></span><div class="footer-nav-links"><a variant="text" href="/premium" target="">Pricing</a><a variant="text" href="/consulting" target="">Consulting</a><a variant="text" href="/quickstart.html" target="">Documentation</a><a variant="text" href="/chat" target="_blank">Discord</a><a variant="text" href="/code" target="_blank">Github</a><a variant="text" href="https://twitter.com/intent/user?screen_name=rxdbjs" target="_blank">Twitter</a><a variant="text" href="https://www.linkedin.com/company/rxdb" target="_blank">LinkedIn</a></div></div><div class="footer-policy"><div><a variant="text" href="/legal-notice" target="_blank">Legal Notice</a></div><span class="footer-rights">© 2024 RxDB. All rights reserved.</span></div><img class="footer-img desktop-img" src="/img/footer-column.svg" alt="columns"></div></div></div>
</body>
</html>