Yes — it’s possible, and it’s a pretty natural extension if you’re willing to treat “documents” as a universal substrate and add a few missing pieces (identity, types, security, and interoperability). A document-CRDT gives you the hardest part for the web already: offline-first, concurrent edits, and deterministic convergence without central coordination.
Here’s what it takes to turn a document CRDT system into a distributed object framework.
1) Map “objects” onto CRDT-backed documents
A distributed object framework needs:
Object identity (stable IDs)
Object state (fields / collections)
Methods / behavior (logic)
References (object graph edges)
Consistency model (what clients can assume)
A document CRDT can represent object state in at least two workable ways:
A. “One object = one CRDT document”
Each object is a CRDT map (or JSON-like tree). References are IDs.
Pros: clean modularity, caching, per-object access control
Cons: lots of small docs, cross-object transactions are tricky
B. “Object graph = one CRDT document”
All objects live inside a single CRDT tree (e.g., objects[id] = {...}).
Pros: easy traversal, atomic multi-object edits (within one doc)
Cons: access control and partial replication are harder
In both cases, you end up with replicated stateful objects whose fields are CRDTs (registers, maps, sets, lists, counters).
2) Add a type system on top of “generic JSON”
Document CRDTs often operate on generic structures (text, maps, lists). A framework needs stronger semantics:
Typed fields: counter, lww_register, mv_register, orset, rga_list, etc.
Schema evolution: forward/backward compatible changes
Validation: reject/ignore invalid operations deterministically
Key point: validation must be pure and deterministic, or else replicas can diverge. A common approach:
Accept ops structurally, but mark invalid ones as “tombstoned” or no-ops consistently.
Or restrict the op language so invalid states are unrepresentable.
3) Decide how “methods” work (commands vs events vs reducers)
Objects aren’t just state; they have behavior. You can do this a few ways:
Option 1: Local-first reducers (“pure functions on CRDT state”)
Clients call methods that compile into CRDT ops.
Best for: collaborative apps, offline-first UX
Challenge: side effects (payments, emails) can’t be “pure CRDT”
Option 2: Event-sourced commands + CRDT materialization
Methods emit events; state is derived (possibly into CRDT structures).
Best for: auditable systems, complex workflows
Challenge: making event processing deterministic across replicas
Option 3: Capability-secured remote procedures + replicated state
“Methods” are RPCs to a service, but state sync remains CRDT-based.
Best for: side effects, compliance, authority
Challenge: you lose some “fully decentralized” feel
A practical web framework often blends these:
CRDT for shared UI state
Server authority for side effects / invariants
4) Handle references, loading, and partial replication
A distributed object framework needs “webby” mechanics:
Links: object A references object B by ID (like URLs)
Resolvers: fetch/sync on demand
Partial replication: don’t sync everything, only what you need
Indexing/querying: CRDT state is not automatically query-friendly
Common solutions:
Maintain materialized indexes (also CRDTs or derived views)
Use subscriptions by object ID and by query
Allow “views” that are re-computable from state
5) Security: auth is not optional
CRDT convergence doesn’t solve “who is allowed to do what.”
You typically need:
Per-operation authentication (signed ops)
Authorization rules (ACLs or capabilities)
Encryption (at rest and ideally end-to-end)
Key rotation / revocation story
Two patterns:
ACL / policy server
Server filters ops; clients can’t apply unauthorized ops.
Easier revocation
More centralized
Capability-based (object capabilities)
Possession of an unforgeable token/key grants rights.
More decentralized
Revocation is harder; often time-bounded capabilities help
6) Cross-object invariants and “transactions”
CRDTs are great when operations commute. But object frameworks often need invariants:
“Balance can’t go below 0”
“Username must be unique”
“Move item from A to B exactly once”
You can’t get all invariants in a fully concurrent CRDT world without tradeoffs.
Your options:
Design invariants as monotonic / commutative (best case)
Use escrow / bounded counters for “can’t exceed X” constraints
Introduce coordination (locks/leases/consensus) for the hard cases
Accept eventual violation + repair (compensating actions)
A good framework makes this explicit: most objects are coordination-free; some operations require coordination.
7) Interop: make “object ops” a portable protocol
To be a web framework rather than an app-specific system, you want:
A canonical op format (binary or JSON)
Stable IDs (UUID/ULID + actor IDs + Lamport/time)
Versioned schemas
Deterministic merge rules
If the protocol is stable, any web client can participate.
What you get if you do this well
Offline-first distributed objects with “real-time” collaboration
Conflict-free shared state by default
Multi-device sync “for free”
A nice programming model: “objects that just converge”
The big pitfalls
Performance (metadata growth, tombstones, causal history)
Query/index complexity (CRDT state ≠ database query engine)
Security/revocation (especially end-to-end)
Invariants (some business rules need coordination)
UX surprises (eventual consistency is user-visible unless designed around)
A concrete “minimal architecture” that works
Each object is a CRDT document (map/tree) with typed fields
Operations are signed and versioned
Clients run pure reducers that produce CRDT ops
A relay/server provides:
discovery + transport (WebSocket/WebRTC)
authorization filtering
persistence
optional coordination endpoints for “hard” operations
Derived indexes/views for queries
If you tell me what kind of “distributed objects” you mean (UI components? shared domain models like tasks/files? or general-purpose remote objects with methods and side effects?), I can sketch a more specific design (data model + op format + method semantics) that fits that use case.