Getting started
Getting started
DXOS is the developer platform for collaborative, offline-first, privacy-preserving software.
Learn about the mission.
In this guide
- Starting a react project with an app template.
- Using ECHO for real-time state consensus in
react
. - Using HALO for decentralized identity.
- Starting a KUBE to host the app.
- Deploying the app to KUBE.
Create an app
DXOS project templates are based on vite
, typescript
, react
, tailwind
, pwa
, and other opinions to get you going quickly.
DXOS works in any Node.js or Browser environment. There is a TypeScript API and a react
API.
This guide will walk you through creating and deploying a react
app.
Ensure node -v
is at version 18 or higher (recommend Node Version Manager).
First, create a new empty folder
mkdir hello
cd hello
Initialize the app with npm init
like this:
npm init @[email protected]
Note
If you encounter an error with EINVALIDPACKAGENAME
it's likely the npm/node versions are out of date. Ensure node -v
is 18 or higher and npm -v
is 9 or higher.
Then, use your favorite package manager such as yarn
, npm
or pnpm
:
pnpm install
pnpm serve
This will start the development server and print its URL ๐.
Now it should be possible to open two windows to that URL and see reactive updates like in the video below.
Why this is cool:
- State is being reactively shared between all instances of the app running on the same device. If more peers join the space, all of them will see updates reactively.
- Data is stored locally, in-browser, in IndexedDB, controlled by the
halo.dxos.org
domain. This enables privacy and gives end-users control over their data. The app running onlocalhost
subscribes to data through a local shared memory connection with the HALO PWA onhalo.dxos.org
which is fast and works offline. Learn more about the HALO vault topology. - When remote peers join the same space, their changes are given to running apps through HALO in the same way.
- Remote peers exchange data directly, peer-to-peer over secure WebRTC connections.
- User identity (public/private keys) are established securely and maintained by HALO for the whole device (browser profile), without a password.
- Everything works offline.
- Real-time collaboration is possible when online.
- There are no servers that store any data.
- There is no need for ORMs. ECHO objects are "plain javascript" objects that can be manipulated directly.
- There is no need for an API tier. The app has everything it needs on the client.
ECHO State Consensus
ECHO is a peer-to-peer graph database designed for offline-first and real-time collaboration. There is no central server, peers exchange data directly over p2p connections.
How to use ECHO
- Install
@dxos/client
or@dxos/react-client
forreact
usingnpm
,yarn
, orpnpm
. - Create and initialize a Client or use a
<ClientProvider />
inreact
. - Establish a HALO identity.
- Create or join a space.
- Find objects with
query
oruseQuery
inreact
. - Mutate the objects as you would plain JavaScript objects, and they will replicate with other peers for you. ๐
import React from 'react';
import { createRoot } from 'react-dom/client';
import {
ClientProvider,
useIdentity,
useQuery,
useSpaces
} from '@dxos/react-client';
const Component = () => {
// Get the user to log in before a space can be obtained.
const identity = useIdentity({ login: true });
// Get the first available space, created with the identity.
const [space] = useSpaces();
// Grab everything in the space.
const objects = useQuery(space, {});
// Show the id of the first object returned.
return <>{objects[0]?.id}</>;
};
const App = () => (
<ClientProvider>
<Component />
</ClientProvider>
);
createRoot(document.body).render(<App />);
Tip
To see an example without react
see the TypeScript Guide
Mutations
Any objects coming from query
or useQuery
are tracked. Manipulate them directly:
import React from 'react';
import { useQuery, useSpace } from '@dxos/react-client';
// ensure there is a ClientProvider somewhere in the tree above
export const Component = () => {
const space = useSpace('<space-key>');
const objects = useQuery(space, {});
return (
<div
onClick={() => {
// mutate objects directly and they will be replicated to all peers
const object = objects[0];
object.counter = 0;
object.name = 'example';
}}
></div>
);
};
The above writes will start propagating to connected peers in the space on the next tick.
The changes will also cause any subscribed UI components in the app to re-render accordingly as well.
Creating new objects:
import React from 'react';
import { useQuery, useSpace } from '@dxos/react-client';
import { Expando } from '@dxos/react-client';
// ensure there is a ClientProvider somewhere in the tree above
export const Component = () => {
const space = useSpace('<space-key>');
return (
<div
onClick={() => {
// create an Expando object for storing arbitrary JavaScript objects
const note = new Expando({ title: 'example' });
note.description = 'Expandos can have any additional properties.';
// call this once per object
// subsequent mutations will be replicated to all peers
space!.db.add(note);
}}
></div>
);
};
This will begin tracking further changes on the object and replicating them to other peers.
Recap
- A HALO identity and a space are required to use ECHO.
- Reading objects is as simple as
space.query()
in TypeScript oruseQuery()
inreact
. - The objects returned are tracked by the
Client
and direct mutations to them will be synchronized with other peers (and other parts of your app) reactively.
Next steps
Continue reading below about how to deploy and host the app, or jump to:
- ECHO with React
- ECHO with TypeScript
- ECHO with strongly typed objects
Starting a KUBE
KUBE hosts and serves applications and provides supporting services like peer network discovery.
Install KUBE:
sudo bash -c "$(curl -fsSL https://install-kube.dxos.org)"
Then:
sudo kube start # start the service in the background
kube status # verify it's running
Once KUBE is running, applications can be deployed to it. ๐
Learn more about what services KUBE provides.
Deploying apps to KUBE
To deploy to KUBE, first ensure a KUBE is running as above.
If using a DXOS application template:
pnpm run deploy
Otherwise, to deploy any static application:
The app will be accessible in a browser at http://<app-name>.localhost
where <app-name>
is found in dx.yml
. ๐
For example, and app created with dx app create hello
, the app will be on hello.localhost
by default.
Caution
Your app will now always be available on your machine until KUBE or the specific app is stopped.
Tunneling
KUBE can expose apps to the world wide web and provide URLs that can be used to reach them from anywhere on the internet.
Simply set tunnel: true
in dx.yml
and redeploy. Read more about KUBE tunneling
.
Next steps
This guide demonstrated how to create and deploy a local-first DXOS application.
Using DXOS:
- ECHO with React
- ECHO with TypeScript
- ECHO with strongly typed objects
We hope you'll find the technology useful, and we welcome your ideas and contributions:
- Join the DXOS Discord
- DXOS repository on GitHub
- File a bug or idea in Issues
Happy building! ๐