Skip to content

Local development

Use this guide to develop Synchro itself. For application integration, start with First synchronization.

Run Make commands from the repository root. Create ordinary work branches from dev and target their pull requests at dev. master is the stable default branch, not the target for unfinished development. The integration setup creates test tables, grants, registrations, and seed data. Never point it at a production database or a database with application data.

Work Prerequisites
Server and Go Go 1.25, Rust 1.92, cargo-pgrx 0.17, PostgreSQL 18, C build tools
Swift and iOS macOS, Xcode, Swift 6, an installed iOS simulator
Kotlin and Android JDK 17, Android SDK, platform tools, the required emulator image
React Native Node 22.20.0, Corepack/Yarn 4.11.0, the platform tools above, CocoaPods for iOS
Documentation Node 22.12 or later in the supported Node 22 line, npm, Python 3

Configure pgrx for the PostgreSQL installation you will use. PGRX_PG_CONFIG must name that installation’s executable pg_config. The default comes from the pg18 entry in ~/.pgrx/config.toml. The pgrx configuration and actual binaries must refer to the same PostgreSQL installation.

Android targets use ANDROID_HOME for the SDK and ANDROID_JAVA_HOME for JDK 17. Set both to your installed tool locations. Install the SDK platform and build-tools versions declared in the Android Gradle projects. Start the emulator required by the selected test target.

The CI emulator runner caches its pinned archive at $ANDROID_HOME/.synchro-cache/16428233/emulator.zip. It verifies the archive size and SHA-256 before each installation. Remove that cache file if validation reports damaged bytes.

Install the React Native workspace dependencies before bridge checks:

Terminal window
cd clients/react-native
corepack enable
corepack yarn install --immutable
cd ../..

Choose the checks relevant to your change:

Terminal window
make test-rust-core
make test-swift-unit
make test-kotlin-unit
make test-rn-unit
make docs-build

Run only platform targets supported by your installed toolchain. These commands do not replace the complete Candidate workflow.

Build fresh immutable artifacts in a clean checkout:

Terminal window
make conformance-adapter-artifact
make conformance-seed-artifact
make conformance-pg18-extension-test-artifact
make conformance-update-baseline-extension-artifact

The extension update tests need the bundles from make conformance-update-baseline-extension-artifact. Set SYNCHRO_CONFORMANCE_UPDATE_BASELINE_EXTENSION_ARTIFACT to the baseline bundle. Set SYNCHRO_CONFORMANCE_UPDATE_ORIGIN_EXTENSION_ARTIFACTS to the directory of later released origins. extensions/synchro-pg/update-origins.json pins each later released origin by version and archive digest. The artifact targets refuse to replace existing output directories. After implementation changes, use a fresh worktree and rebuild the artifacts rather than accidentally testing stale output. The update baseline and origin bundles are pinned published release assets. The other artifacts are local test inputs, not a published release.

In the first terminal, run:

Terminal window
make local-postgres-run

Keep this process running. It creates an isolated PostgreSQL instance, role credentials, and a private connection file. The default state directory is .ignore/r2/tmp/local-postgres. Wait until its attach.env and postgres.url files exist.

In a second terminal at the repository root, load that fixture:

Terminal window
export SYNCHRO_ATTACH_DIR="$PWD/.ignore/r2/tmp/local-postgres"
export WARM_CONNECT_ENV_FILE="$SYNCHRO_ATTACH_DIR/attach.env"
set -a
. "$WARM_CONNECT_ENV_FILE"
set +a
export ADAPTER_TEST_URL="$(cat "$SYNCHRO_ATTACH_DIR/postgres.url")"
export SYNCHRO_TEST_JWT_SECRET="$(cat "$SYNCHRO_CONFORMANCE_JWT_SECRET_FILE")"

Do not print or commit these values. The connection file authorizes test setup in this disposable instance.

The native and bridge Make targets prepare and start their adapter as needed:

Terminal window
make test-swift
make test-kotlin
make test-rn-e2e-ios
make test-rn-e2e-android

Run these sequentially when they share the fixture, simulator, emulator, or package output. Use conformance guidance for focused selectors and server-side suites.

For manual requests, start the foreground adapter instead:

Terminal window
make synchrod-pg-test-serve

It prepares the disposable integration schema before listening on port 8091. Add CLIENT_DATASET=1 to also prepare the synthetic training dataset in conformance/dataset and its authored seed. That dataset registers the shared catalog scope, so every user in that database receives it. Do not run another adapter owner on that port. The helper rejects an occupied port rather than terminating its owner.

Each test job in .github/workflows/ci.yml calls one make ci-<job> target. Run the same target to run the same test commands as CI:

Terminal window
make ci-source-quality
make ci-candidate-server
make ci-candidate-swift
make ci-candidate-kotlin
make ci-candidate-rn-ios
make test-rn-e2e-android-build
make ci-candidate-rn-android

The workflow file keeps only tool setup, device setup, database start and stop, and artifact upload. Install the tools and boot the device that the job sets up before you run its target. The server candidate target creates its API-test fixture after the Rust targets. It stops that fixture before the independent black-box and integration mutation targets. Do not start a separate fixture for the server candidate target. Failed API fixture logs remain under .ignore/r2/tmp/candidate-server-adapter.*.

The native candidate targets need a disposable database. They read its URL from ADAPTER_TEST_URL and its attach.env file from WARM_CONNECT_ENV_FILE.

For a native candidate database on this machine, start it as CI does:

Terminal window
make local-postgres-start
export ADAPTER_TEST_URL="$(cat .ignore/r2/tmp/local-postgres/postgres.url)"
export WARM_CONNECT_ENV_FILE="$PWD/.ignore/r2/tmp/local-postgres/attach.env"

For a database on another machine, set ADAPTER_TEST_URL to its URL. Set WARM_CONNECT_ENV_FILE to a local copy of its attach.env file. After the run, stop the fixture with make synchrod-pg-test-stop and make local-postgres-stop.

make ci-candidate-server fetches the pinned update baseline bundles again on each run.

Stop the adapter before the database:

Terminal window
make synchrod-pg-test-stop

Then press Control-C in the first terminal. The provisioner closes its database and removes its generated credentials. Do not terminate unrelated port owners or delete another process’s state directory.

Local logs, credentials, build output, and test reports must remain outside tracked source. Use RELEASE.md for release operations.