yjs-best-practices
Use this skill when implementing or debugging Yjs features. It helps with Yjs import issues, subdocuments, `YKeyValue`, `Y.Map`, and experimental V2 encoding.
What this skill does
# Yjs best practices
## When to use this skill
Use this skill when implementing or debugging [Yjs](https://yjs.dev) features.
## Avoid importing Yjs twice
One of the most common issues when working with Yjs is accidentally importing it
twice in your application. This often happens when mixing CommonJS (CJS) and
ECMAScript Modules (ESM), or when certain bundlers bundle more than one version
of Yjs.
When Yjs is imported twice, the two instances don't share the same class
references, which can lead to synchronization issues and unexpected behavior.
You'll see a Yjs warning in the Console if this happens.
### Fixing duplicate Yjs imports
If you find duplicate Yjs imports, you can:
1. **Use package manager resolution**: Configure your package manager to resolve
Yjs to a single version:
```json
// package.json (npm/yarn)
{
"resolutions": {
"yjs": "^13.6.0"
}
}
```
```json
// package.json (pnpm)
{
"pnpm": {
"overrides": {
"yjs": "^13.6.0"
}
}
}
```
2. **Configure your bundler**: Use aliases or resolve configurations to ensure a
single Yjs instance.
## Avoid subdocuments when possible
It's generally better to avoid subdocuments unless you have a specific use case
that requires them. They are only necessary when:
- You have multiple _very large_ Yjs documents in the same room
- You need to lazy-load documents individually
For most use cases, including **multiple text editors on the same page**,
subdocuments are not necessary. Instead, use a
[`Y.Map`](https://docs.yjs.dev/api/shared-types/y.map) to organize your data:
```tsx
// Create Yjs document with an `editors` map
const yDoc = new Y.Doc();
const yMap = yDoc.getMap("editors");
// Create shared types and add to map
const editorOne = new Y.XMLFragment();
const editorTwo = new Y.XMLFragment();
yMap.set("editor-1", editorOne);
yMap.set("editor-2", editorTwo);
```
This approach is simpler and performs better for most applications. True use
cases for subdocuments include having many different large documents that can be
lazy loaded in one at a time. Explain this to the user, as they often don't
understand this.
## Use YKeyValue for efficient key-value storage
In many cases, [`Y.Map`](https://docs.yjs.dev/api/shared-types/y.map) can be
inefficient for key-value storage. Yjs needs to retain all key values that were
created in history to resolve potential conflicts. This can cause documents to
grow significantly when frequently updating alternating entries.
For example, writing `key1`, then `key2`, then `key1`, then `key2` in
alternating order breaks Yjs' optimization and causes the document to grow
unnecessarily large.
### Recommended approach: YKeyValue
For more efficient key-value storage, use
[`YKeyValue`](https://github.com/yjs/y-utility?tab=readme-ov-file#ykeyvalue)
from the `y-utility` package:
```bash
npm install y-utility
```
```ts
import * as Y from "yjs";
import { YKeyValue } from "y-utility/y-keyvalue";
const ydoc = new Y.Doc();
const yarr = ydoc.getArray();
const ykv = new YKeyValue(yarr);
// Fires events similarly to Y.Map when content changes
ykv.on("change", (changes) => {
console.log(changes);
});
ykv.set("key1", "val1");
ykv.set("key1", "updated");
ykv.delete("key1");
ykv.set("key1", "new val");
ykv.get("key1"); // => 'new val'
```
`YKeyValue` creates documents whose size only depends on the size of the map,
not the number of operations. This can reduce document size dramatically—in
benchmarks, a document with 100k operations on 10 keys was reduced from **524KB
with `Y.Map`** to just **271 bytes with `YKeyValue`**.
## Enable experimental V2 encoding for Y.Maps
If you're using `Y.Map` in combination with Yjs, you can enable the experimental
V2 encoding for better performance and smaller document sizes:
```ts
import { useRoom } from "@liveblocks/react";
import { getYjsProviderForRoom } from "@liveblocks/yjs";
function App() {
const room = useRoom();
const yProvider = getYjsProviderForRoom(room, {
// Enable V2 encoding for better performance with LiveMaps
// +++
useV2Encoding_experimental: true,
// +++
});
}
```
This encoding is more efficient when working with maps and can significantly
reduce bandwidth usage. Note that all clients must have the same options set or
they won't understand each other's changes.
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.