diff --git a/apps/web/pages/docs/_meta.json b/apps/web/pages/docs/_meta.json
index 4da8a2d54..9430b06b3 100644
--- a/apps/web/pages/docs/_meta.json
+++ b/apps/web/pages/docs/_meta.json
@@ -3,6 +3,7 @@
"installation": "Installation",
"quickstart": "Quickstart",
"api": "API",
+ "patterns": "Patterns",
"evolu-server": "Evolu Server",
"how-evolu-works": "How Evolu Works",
"comparison": "Comparison",
diff --git a/apps/web/pages/docs/patterns.mdx b/apps/web/pages/docs/patterns.mdx
new file mode 100644
index 000000000..02d807392
--- /dev/null
+++ b/apps/web/pages/docs/patterns.mdx
@@ -0,0 +1,42 @@
+import { Callout } from "nextra-theme-docs";
+
+# Patterns
+
+## Deferred Sync with Local-Only Tables
+
+Tables with a name prefixed with `_` are local only, which means they are never
+synced. It's useful for device-specific or temporal data.
+
+Imagine editing a JSON representing a rich-text formatted document. Syncing the
+whole document on every change would be inefficient. The ideal solution could
+be to use some advanced CRDT logic, for example, the
+[Peritext](https://www.inkandswitch.com/peritext), but a reliable implementation
+doesn't exist yet.
+
+Fortunately, we can leverage Evolu's local-only tables instead. Saving huge
+JSON on every keystroke isn't an issue because Evolu uses Web Workers,
+so saving doesn't block the main thread. In React Native, we use
+`InteractionManager.runAfterInteractions` (soon).
+
+
+ Is postMessage slow? No, not really. (It depends.)
+ [surma.dev/things/is-postmessage-slow](https://surma.dev/things/is-postmessage-slow)
+
+
+When we decide it's time to sync, we move data from the local-only table to the
+regular table. There is no API for that; just set `isDeleted` to `true` and insert
+data into a new table. Evolu batches mutations in microtask and runs it within a
+transaction, so there is no chance for data loss.
+
+```ts
+// Both `update` and `create` run within a transaction.
+evolu.update("_todo", { id: someId, isDeleted: true });
+// This mutation starts syncing immediately.
+evolu.create("todo", { title });
+```
+
+The last question is, when should we do that? We can expose an explicit sync
+button, but that's not a friendly UX. The better approach is to use a reliable
+heuristic to detect the user unit of work. We can leverage page visibility,
+a route change, and other techniques. Unfortunately, we can't rely on unload
+event because it's unreliable. **Evolu will release a helper for that soon.**
diff --git a/packages/evolu-common-web/src/index.ts b/packages/evolu-common-web/src/index.ts
index 35857a434..873102099 100644
--- a/packages/evolu-common-web/src/index.ts
+++ b/packages/evolu-common-web/src/index.ts
@@ -15,7 +15,10 @@ import {
} from "./PlatformLive.js";
/**
- * Create Evolu for web.
+ * Create Evolu for the web.
+ *
+ * Tables with a name prefixed with `_` are local only, which means they are
+ * never synced. It's useful for device-specific or temporal data.
*
* @example
* import * as S from "@effect/schema/Schema";
@@ -31,6 +34,8 @@ import {
* type TodoTable = S.Schema.To;
*
* const Database = S.struct({
+ * // _todo is local only table
+ * _todo: TodoTable,
* todo: TodoTable,
* });
* type Database = S.Schema.To;
diff --git a/packages/evolu-react-native/src/index.ts b/packages/evolu-react-native/src/index.ts
index 9a7780e0a..937244fff 100644
--- a/packages/evolu-react-native/src/index.ts
+++ b/packages/evolu-react-native/src/index.ts
@@ -67,11 +67,18 @@ const EvoluNativeLive: Layer.Layer<
);
/**
- * Create Evolu for web.
+ * Create Evolu for React Native.
+ *
+ * Tables with a name prefixed with `_` are local only, which means they are
+ * never synced. It's useful for device-specific or temporal data.
*
* @example
* import * as S from "@effect/schema/Schema";
- * import { NonEmptyString1000, createEvolu, id } from "@evolu/react";
+ * import {
+ * NonEmptyString1000,
+ * createEvolu,
+ * id,
+ * } from "@evolu/react-native";
*
* const TodoId = id("Todo");
* type TodoId = S.Schema.To;
@@ -83,6 +90,7 @@ const EvoluNativeLive: Layer.Layer<
* type TodoTable = S.Schema.To;
*
* const Database = S.struct({
+ * // _todo is local only table
* todo: TodoTable,
* });
* type Database = S.Schema.To;