Thank you for your interest in helping build FlutterSync! This document explains how to set up a development environment, what kinds of contributions are most useful right now, and the workflow we follow.
FlutterSync is early-stage — the architecture is complete and the test suite is green, but no adapter has been validated against a live backend yet. Your contribution can have a real, visible impact.
This project follows the Contributor Covenant 2.1. By participating you agree to abide by its terms.
| Area | Why it matters | Effort |
|---|---|---|
Validate SupabaseSyncAdapter against a real project |
Compiles today, never run against a live Supabase. Most-requested backend. | Medium |
Validate FirebaseSyncAdapter against Firestore |
Same as above. | Medium |
Validate RestSyncAdapter against a real REST server |
Generic; any tutorial backend works. | Small |
| Real device background sync — Android (WorkManager) | Code is API-correct, never run on a device. | Medium |
| Real device background sync — iOS (BGTaskScheduler) | Notoriously hard to test; needs Apple hardware. | Medium-Large |
| Web ServiceWorker bridge (the JS side) | Dart side exists; the actual flutter_sync_sw.js is missing. |
Medium |
| Wider CRDT property tests (10k seeds, more replicas) | Current 20-seed suite already caught a LWWMap bug — there are likely more. |
Small |
Drift OutboxQueue (persistent variant) |
Today only InMemoryOutboxQueue is wired up. |
Medium |
| Performance benchmarks | No data yet on HLC ticks/sec, outbox throughput, large-batch behavior. | Small-Medium |
| Tutorials — "Building X with FlutterSync" | Documentation is reference-style; we need stories. | Small per tutorial |
See ROADMAP.md for the longer-term plan.
Requires Flutter ≥ 3.19 and Dart ≥ 3.3.
# Clone
git clone https://github.com/alessonqueirozdev-hub/flutter_sync.git
cd flutter_sync
# Install dependencies
flutter pub get
# Verify everything is green before you start
dart format --output=none --set-exit-if-changed .
dart analyze --fatal-infos --fatal-warnings
flutter testTo run the example app:
cd example
flutter pub get
flutter run -d chrome # or -d windows, -d macos, -d linux, -d <android-device-id>main ← protected; v0.1.x releases, squash-merges from develop only
develop ← integration; PRs land here first
└── feat|fix|docs|chore/<short-name> ← your work happens here
Branch naming: lowercase kebab-case prefixed feat/, fix/, docs/, chore/, ci/. Examples:
feat/supabase-batch-retryfix/lww-set-tombstone-leakdocs/getting-started-supabase
Always branch from develop, never from main.
We use Conventional Commits for community contributions:
type(scope): imperative description (≤72 chars)
Optional longer body explaining *why*, not *what*. Wrap at 72 chars.
Types: feat · fix · test · docs · chore · refactor · ci · perf · style
Scope: lowercase layer/module — hlc, outbox, crdt, models, core, store, scheduler, supabase-adapter, firebase-adapter, rest-adapter, graphql-adapter, grpc-adapter, mock-adapter, encryption, audit, migrations, logging, bandwidth, devtools, example, readme.
Good examples:
feat(supabase-adapter): retry push on connection reset
fix(crdt): make LWWMap merge commutative on HLC ties
test(hlc): add property tests for receive() drift detection
docs(getting-started): add Firebase quickstart
Notes:
- Historical commits use a
[NNN]sequential prefix ([001]through[178]). This was an internal cataloging convention; contributors do not need to follow it. Maintainers may add a number on merge. - No emojis in commit subjects.
- No ticket references in subjects (they go in the body if needed).
- One logical change per commit. Two files in one commit is fine if they belong to the same change (e.g. source + its test).
- Fork the repo, branch from
develop, make your change. - Run the local gate (see Development setup).
- Open a PR against
developwith a clear description (the template will guide you). - CI must be green before review. CI runs
dart analyze,dart formatcheck, andflutter test. - A maintainer reviews. Expect comments — this is a young codebase and we are still discovering good patterns together.
- Squash-merge when approved.
For larger changes (new adapter, breaking change, schema migration), please open an issue or a Discussion first so we can talk through the design.
- Dart 3.3+ with the full lint set from
analysis_options.yaml. dart formatis the formatter. No exceptions.- Use
sealed classfor unions;pattern matchingin everyswitchover a sealed class (exhaustiveness required). - All immutable fields are
final. Value objects are@immutable. - Every public class, method, and field has a
///DartDoc with a complete first-sentence summary. - No
dynamicin public APIs. Nolatein public APIs without DartDoc rationale. - Never use
throw UnimplementedError()as a stub body. - Never leave
// TODO,// FIXME,// XXX,// HACKin committed code. Open an issue instead.
- Public streams are
broadcastby default. - Every
StreamControlleris closed indispose(). EveryStreamSubscriptionis cancelled. .distinct()on all status streams to suppress duplicate emissions.
- Never use exceptions for control flow.
- Use
SyncResult<T, E>(or typed exceptions) for fallible operations. - Log every error through
SyncLoggerbefore propagating. - Heavy work (Argon2id derivation, AES of large batches, delta computation > 1000 records) runs in
Isolate.run().
Every PR that adds logic must add tests. Coverage targets:
| Component | Target |
|---|---|
| Overall package | 80% |
Core engine (lib/src/core/) |
95% |
| HLC | 100% |
| Conflict resolvers | 100% |
| CRDTs | 100% |
| Outbox | 90% |
Categories you should cover for any non-trivial class:
- Unit — happy path, boundary values, invalid inputs, empty state, serialization round-trip.
- Behavioral — offline behavior, retry attempts and delays, conflict outcomes, multi-client simulation.
- Integration — full
write → outbox → push → pull → resolve → applycycle. - Property-based — for CRDTs, random op sequences on N replicas in random orders; final state must converge on every replica.
Run a single test file:
flutter test test/path/to/file_test.dartRun with coverage:
flutter test --coverage
genhtml coverage/lcov.info -o coverage/htmlBy contributing you agree your work is released under the Apache 2.0 License.
Every new .dart file must include the SPDX header on its first two lines:
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 The FlutterSync Authors. All rights reserved.Do not open a public issue for security vulnerabilities. See SECURITY.md.
Use the GitHub issue templates:
For open-ended questions or design discussions, use GitHub Discussions.
If something isn't clear, open a Discussion. Helping us improve this guide is itself a contribution.
Thank you for being here.