>
);
};
```
## Checking your work
We've finished wiring up the UI, we've got link sharing via the URL hash and storage and synchronization between tabs. If you open the application in one tab, then copy the URL and open it in another you should be able to create new tasks, toggle their done state, and update the description and see the changes synchronize between tabs.
Next, to sync over the network.
# [Network Sync](https://automerge.org/docs/tutorial/network-sync/)
## Collaborating over the internet
Thus far, we've been using the BroadcastChannel NetworkAdapter to move data between tabs in the same browser. Automerge treats all network adapters similarly: they are just peers you may choose to synchronize documents with.
One straightforward way of getting data to other people is to send it to the cloud; then they can come along and fetch the data at their leisure.
When you configure automerge to run on an internet server, listen for connections, and store data on disk, then we call that a "sync server". There's nothing really special about a sync server: it runs the exact same version of Automerge as you run locally. With a little configuration work, you could even connect to multiple sync servers and choose what data you want to send.
The Automerge team provides a public community sync server at `wss://sync.automerge.org`. For production software, you should run your own server, but for prototyping and development you are welcome to use ours on an "as-is" basis.
### Exercise
#### Connect to a sync server via a websocket
This is as simple as adding `WebSocketClientAdapter` to your Repo's network subsystem. We'll do this at creation time, but remember you can add and remove adapters later, too.
#### Solution
```tsx title="src/main.tsx"
//...
// highlight-next-line
import { WebSocketClientAdapter } from "@automerge/react";
const repo = new Repo({
network: [
new BroadcastChannelNetworkAdapter(),
// highlight-next-line
new WebSocketClientAdapter("wss://sync.automerge.org"),
],
storage: new IndexedDBStorageAdapter(),
});
```
Now, when the Repo sees any changes it will sync them not only locally via the BroadcastChannel, but also over a websocket connection to `sync.automerge.org`, and any other process can connect to that server and use the URL to get the changes we've made.
#### Caution
The Automerge project provides a public sync server for you to experiment with, at `sync.automerge.org`. This is not a private instance, and as an experimental service has no reliability or data safety guarantees. Feel free to use it for demos and prototyping, but run your own sync server for production apps.
To see this in action, open the same URL (including the document ID) in a different browser, or on a different device. Unlike the local-only version, you'll now see the data updates synced across _all_ open clients.
{{ figure  Local collaboration via the BroadcastChannelNetworkAdapter }}
## Network Not Required
Now that the Repo is syncing changes remotely, what happens when the websocket connection is unavailable?
Since the repo stores documents locally with the `IndexedDBStorageAdapter`, methods like `Repo.find` will consult local storage to retrieve/modify documents, so clients can create new documents while disconnected, and any clients who've already loaded a given document will still be able to make changes to it while offline.
Once connectivity has been re-established, the Repo will sync any local changes with those from remote peers, so everyone ultimately sees the same data.
Go ahead and experiment with this by opening your site in two browsers, turning off wifi, making some changes, and turning it back on.
# [Multiple Task Lists](https://automerge.org/docs/tutorial/multiple-task-lists/)
You might have noticed that if you lose the URL of a task list, it's gone forever. This is fine for testing and demos, but obviously no good for a real application.
Automerge is built around the document as a building block for your application, and we use `AutomergeUrl` links to connect those documents together. We've already created one kind of document, a task list, and now we're going to build on that foundation by collecting your task lists into something like a folder to keep them organized.
This is going to give us a chance to see a few patterns in action: linking between documents with URLs, working with multiple documents at once, and using a single document as the "entry point" for your application.
You can think of the "entry point" as being akin to a user's account. By synchronizing that document between their devices, a user can get access to their documents from multiple browsers or devices, but be careful: until we implement some kind of security on the sync server, a user's privacy relies on their not sharing that "root" document ID with anyone else.
Here's the plan. We are going to:
1. Create a new "root" document which links to all the task lists the user has opened.
1. Create some UI to handle switching between several different task lists
2. Register task lists we open or create in that root document (if we don't have them already.)
3. Store the root document's ID in localStorage in a well-known key to check during startup.
4. Create a simple UI for copying the root document between browsers, creating rudimentary "accounts".
If this feels different to you from how a traditional database works, that's normal. With Automerge, building an application will feel more like linking together a web of documents than querying a database.
## Create a root document
Our root document is going to track all the task lists the user has created or opened. Let's add a type for it in `src/rootDoc.ts`:
```typescript file="src/rootDoc.ts"
import { type AutomergeUrl } from "@automerge/react";
export type RootDocument = {
taskLists: AutomergeUrl[];
};
```
It's just a list of `AutomergeUrl`s, each of which points to a document containing a task list.
Intially we'll create a new root document on every page load and we'll put the URL of the current task list in that root document. This will allow us to focus on the UI work but then we'll come back and add the logic to persist the root document.
Add this code to `src/main.tsx` to create the root document:
```tsx title="src/main.tsx"
// highlight-next-line
import { RootDocument } from "./rootDoc.ts"
// ..
// Add the repo to the global window object so it can be accessed in the browser console
// This is useful for debugging and testing purposes.
declare global {
interface Window {
repo: Repo;
// We also add the handle to the global window object for debugging
// highlight-next-line
handle: DocHandle