locorda on pub.dev

Sync Engine

BYOB β€” Bring Your Own Backend:
sync via Google Drive, Solid Pod, or any file storage β€” no central server.
No sync protocol to implement. No conflict code to write.

The Vision

What if building offline-first, cloud-synced apps was as simple as annotating your domain classes?

1

Annotate Your Classes

Use RDF mapper and CRDT annotations on your domain models. Define conflict resolution strategies right in your code.

const appVocab = AppVocab(appBaseUri: 'https://locorda.dev/example/personal_notes_app');

@RootResource(appVocab, subClassOf: SchemaCreativeWork.classIri)
class Category {
  @RdfIriPart()
  final String id;

  /// Last writer wins on conflicts
  @RdfProperty(SchemaCreativeWork.name)
  @CrdtLwwRegister()
  final String name;

  /// Immutable - can't be changed after creation
  @RdfProperty(SchemaCreativeWork.dateCreated)
  @CrdtImmutable()
  final DateTime createdAt;

  /// Preserve unmapped triples for interoperability
  @RdfUnmappedTriples(globalUnmapped: true)
  final RdfGraph other;

  Category({
    required this.id,
    required this.name,
    DateTime? createdAt,
    RdfGraph? other,
  }) : createdAt = createdAt ?? DateTime.now(),
       other = other ?? RdfGraph();
}
2

Connect User Storage

Use our pre-built UI widgets. Users connect their own Google Drive, Solid Pod, or other storage with simple clicks β€” bringing the unhosted philosophy of BYOB (Bring Your Own Backend) to Flutter.

Connect Your Storage
πŸ“ Google Drive
πŸ”’ Solid Pod
☁️ Dropbox
3

Sync Automatically

That's it. Your app is now fully synchronized across all devices, using the user's own storage as the cloud backend.

πŸ“±
↔️
☁️
↔️
πŸ’»

Key Features

πŸ”„ Conflict-Free Synchronization

State-based CRDT algorithms ensure safe collaboration without coordination. Multiple devices can edit simultaneously without data loss.

🌐 Semantic Interoperability

All data stored as clean, standard RDF for maximum compatibility. Your data remains accessible and interoperable.

πŸ“± Offline-First

Full offline functionality with automatic sync when connectivity is available. Your app works everywhere.

πŸ”’ Privacy-Preserving

User data stays in their own storage. No vendor lock-in, no centralized database, complete data ownership.

⚑ Performance at Scale

Flexible indexing and fetch strategies keep sync fast as your dataset grows. Tested with ~15k resources; smart sharding is designed to scale further.

🎯 Not a Database

Store your domain instances however you like. The sync engine only handles synchronization, not storage architecture.

Early Access

The core idea works. Try it out, build something real, and tell us what you need.

βœ…

Works Today

  • Google Drive backend β€” fully implemented and tested
  • Offline-first sync with CRDT conflict resolution
  • File-per-resource layout (Solid Pods, linked-data interop)
  • Packed layouts: single-file and sharded (Google Drive)
  • Tested with ~15 000 resources
  • Core application API is stable
🚧

Known Gaps

  • Solid backend: each sync requires many HTTP requests β€” Solid Protocol currently has no batch-write operation. This is a protocol-level limitation, not something we can fix on our side. It is on the Solid roadmap, but progress there is slow.
  • ensure and delete operations not yet implemented
  • Delta layout not yet available β€” the full packed file is uploaded/downloaded each cycle, even for small changes
  • Limited set of CRDT types (LWW register, immutable, OR-Set; more planned)
  • Non-initial sync performance has room for optimization
πŸ”¬

Stability

  • Core application API (annotations, mapper): stable
  • Backend implementation API and exchanged data format (index shards, wire protocol): may have breaking changes
  • Not production-ready yet β€” but definitely worth exploring

Other backends beyond Google Drive are planned. Contributions are very welcome.

Configure Your Storage Layout

Two independent axes give you full control: the layout determines how many cloud files hold your data, while the serialization format determines how each file is encoded.

🌐

File-per-Resource Layout

Required for Solid Pods Β· works everywhere

Each managed resource lives in its own file. Fully linked-data compliant: any Solid-compatible tool or SPARQL client can read and write the data directly.

  • Maximum interoperability with other apps
  • Resources discoverable and addressable by IRI
  • More HTTP round-trips per sync cycle
  • Natural fit for Turtle encoding
Best for: open data, Solid ecosystem
⚑

Packed Layouts

Google Drive, Dropbox & any file-based backend

Multiple resources are grouped into fewer files β€” from a handful of shards down to a single file for the entire dataset. Bulk transfers dramatically reduce round-trips and speed up sync cycles.

  • Far fewer network requests per sync
  • Great fit for Jelly, TriG, or JSON-LD encoding
  • Single-file layout available; single-file-with-delta planned
  • Data not directly accessible by external RDF tools
Best for: private data, performance-critical apps

The serialization format β€” Turtle, Jelly, TriG, JSON-LD β€” is configured independently of the layout. For Solid interoperability Turtle is the natural choice; for packed layouts Jelly gives the best size and decode performance.

Architecture Overview

A 4-layer architecture designed for both simplicity and power.

1

Data Resource Layer

Clean RDF resources using standard vocabularies

2

Merge Contract Layer

Public CRDT rules for conflict resolution

3

Indexing Layer

Efficient change detection and performance optimization

4

Sync Strategy Layer

Application-specific performance trade-offs

What the Engine Generates for You

You never write or read any of this. The actual file stored on a Solid Pod (interoperability mode) for a single Category object β€” generated entirely from the annotations you saw in step 1. Clock vectors, index shard references, blank node mappings: all managed internally.
@prefix category_1762183405043_136175: <https://experiments2.solidcommunity.net/data/aHR0cHM6Ly9sb2NvcmRhLmRldi9leGFtcGxlL3BlcnNvbmFsX25vdGVzX2FwcC92b2NhYnVsYXJ5L3BlcnNvbmFsLW5vdGVzI05vdGVzQ2F0ZWdvcnk=/category_1762183405043_136175#> .
@prefix cm: <https://w3id.org/solid-crdt-sync/vocab/crdt-mechanics#> .
@prefix data: <https://experiments2.solidcommunity.net/data/aHR0cHM6Ly9sb2NvcmRhLmRldi9leGFtcGxlL3BlcnNvbmFsX25vdGVzX2FwcC92b2NhYnVsYXJ5L3BlcnNvbmFsLW5vdGVzI05vdGVzQ2F0ZWdvcnk=/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix idx: <https://w3id.org/solid-crdt-sync/vocab/idx#> .
@prefix mappings: <https://locorda.dev/example/personal_notes_app/mappings/> .
@prefix pn: <https://locorda.dev/example/personal_notes_app/vocabulary/personal-notes#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix schema: <https://schema.org/> .
@prefix smm10v: <https://experiments2.solidcommunity.net/indices/aHR0cHM6Ly93M2lkLm9yZy9zb2xpZC1jcmR0LXN5bmMvdm9jYWIvaWR4I1NoYXJk/index-full-0d7e421f/shard-mod-md5-1-0-v1_0_0#> .
@prefix sync: <https://w3id.org/solid-crdt-sync/vocab/sync#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

data:category_1762183405043_136175 a sync:ManagedDocument;
    foaf:primaryTopic category_1762183405043_136175:it;
    cm:clockHash "d66831f16d25da5c5169b148c9fdeb65";
    cm:createdAt "2025-11-03T15:23:25.160620Z"^^xsd:dateTime;
    cm:hasClockEntry category_1762183405043_136175:lcrd-clk-md5-fe24422ab1fb1e0d69d127bd0c3fd78a;
    idx:belongsToIndexShard smm10v:shard;
    sync:hasBlankNodeMapping category_1762183405043_136175:lcrd-ibn-md5-3c7f9db5b14024d37f19f8dd09ec7c84;
    sync:isGovernedBy (mappings:category-v1.ttl);
    sync:managedResourceType pn:NotesCategory .

category_1762183405043_136175:it a pn:NotesCategory;
    pn:archived false;
    pn:displaySettings _:b1;
    schema:dateCreated "2025-11-03T15:23:25.043734Z"^^xsd:dateTime;
    schema:dateModified "2025-11-03T15:23:25.043738Z"^^xsd:dateTime;
    schema:name "Rot" .

category_1762183405043_136175:lcrd-clk-md5-fe24422ab1fb1e0d69d127bd0c3fd78a cm:logicalTime 1;
    cm:physicalTime 1762183405159 .

category_1762183405043_136175:lcrd-ibn-md5-3c7f9db5b14024d37f19f8dd09ec7c84 sync:blankNode _:b1 .

_:b1 pn:categoryColor "red" .

Common Questions

Clearing up misconceptions about what Locorda requires β€” and what it doesn't.

Does my app need to support Solid Pods?

No. Google Drive is the recommended backend for most apps and is fully implemented and tested today. Solid Pod support exists but comes with a significant limitation: the Solid Protocol currently has no batch-write operation, making each sync cycle slow (many individual HTTP requests). Solid is best suited for open-data and interoperability scenarios. Other backends (Dropbox, custom file storage) are planned.

Do users need a WebID, Solid account, or Semantic Web knowledge?

Only if you choose the Solid backend. With Google Drive, users authenticate via standard Google Sign-In β€” no special accounts, no WebID, no Solid Pod required. The user experience is identical to any other "sign in with Google" app.

Must I use Schema.org, FOAF, or other "generic" vocabularies?

No. Three approaches are supported β€” you choose:

Generated vocabulary (simplest) β€” the code generator derives all IRIs from your Dart class structure and generates the vocab file. Zero manual RDF authoring.
@RootResource(AppVocab(appBaseUri: 'https://myapp.example.com'))
Middle path β€” vocab still generated, but the class is declared as a subclass of an existing type (e.g. schema:CreativeWork) for interoperability.
@RootResource(AppVocab(appBaseUri: '…'), subClassOf: SchemaCreativeWork.classIri)
External vocabulary β€” use external IRIs as-is; annotate each property with @RdfProperty(SchemaCreativeWork.name). No custom vocab file is generated.
@RootResource.externalVocab(SchemaCreativeWork.classIri, 'https://myapp.example.com')

Generic vocabularies are never mandated. Pick whichever approach fits your interoperability needs.

Do I need RDF or Semantic Web expertise to use the sync engine?

Not for everyday use. You annotate your Dart domain classes (@RootResource, @CrdtLwwRegister, …) and the RDF layer is generated and managed entirely by the engine. The complex output in the "What the Engine Generates for You" example above β€” clock vectors, index shard references, blank node mappings β€” is internal engine detail, fully hidden from the application developer.

Basic familiarity with the idea of RDF (data as subject–predicate–object triples) helps when naming your vocabulary IRIs, but you never hand-craft triples or write SPARQL.

Is Locorda only for the Solid / decentralized web ecosystem?

No. The BYOB (Bring Your Own Backend) architecture is storage-agnostic: any file-based storage works. The data format is RDF-based for semantic interoperability, but the auth and storage layer can be Google Drive, Dropbox, or any custom file backend. Solid is one option among several β€” not a prerequisite.

What Can You Build?

πŸ“ Note-Taking Apps

Sync notes across devices using the user's Google Drive or Solid Pod. No backend infrastructure needed.

βœ… Task Managers

Collaborative task lists that sync conflict-free. Each user's data stays in their own storage.

πŸ“š Knowledge Bases

Personal wikis and knowledge graphs that sync seamlessly across devices while preserving semantic structure.

🎨 Creative Tools

Design apps, recipe managers, or any domain-specific tool with built-in sync and data ownership.

Project Scope

πŸ“‹ Specification

Complete architectural documentation for building CRDT-enabled applications with passive storage backends across any programming language.

  • Complete CRDT-RDF architecture with formal vocabulary
  • Language-agnostic design patterns
  • Performance analysis and optimization strategies
  • Interoperability contracts for cross-application compatibility
⚠️ Outdated

The currently published specification is severely outdated. It has significant deviations from the actual implementation, and performance optimization work may cause further changes.

Read Specification β†’

πŸ› οΈ Dart Implementation

A multipackage Dart library that aims to become production-ready for real-world Flutter applications.

  • Full-featured library for collaborative applications
  • Complete API coverage of specification capabilities
  • Performance-optimized for mobile and web
  • Reference example for other language implementations
Implementation Details β†’

Get Involved

This project is open source and welcomes contributions from the community.