Skip to content

Upgrading

Releases, with their notes, are on GitHub Releases. Synclet and its Helm chart are versioned separately. Their change logs are CHANGELOG.md and the chart’s CHANGELOG.md.

  1. Read the release notes of every version between yours and the target, and the version notes below.
  2. Back up the database and keep the encryption key with it. See Backup and Restore.

Each release brings its schema changes as migrations, applied by synclet migrate up. Run it against the database before the new version starts. It applies only the migrations the database lacks, so running it again is harmless. Each module’s migrations hold a PostgreSQL advisory lock while they run, so several migrate up started at once are safe.

  • Helm. The server and jobs pods run synclet migrate up in a migrate init container, so a helm upgrade migrates before the new server starts.
  • Docker Compose. The migrate service runs migrate up, and synclet starts only after it has completed.
  • Binary or plain docker run. Run synclet migrate up yourself, with the new version, before you start it.

synclet migrate status lists applied and pending migrations. To go back to an older version after its migrations ran, restore the backup. synclet migrate down rolls back only the latest migration of one module (--module) or of every module (--all), and needs --yes when ENVIRONMENT is not development.

Executors never touch the database. They talk to the server through the executor API (see Executors). Upgrade them together with the server, from the same release. Synclet does not check that their versions match. Settings > System shows each executor’s version, so an executor left on an old one is easy to spot.

The Helm chart runs the server, jobs worker, executor and the orchestrator container of every sync pod (K8S_EXECUTOR_SYNCLET_IMAGE) from one image, so they move together. Syncs already running when the executor restarts keep their pods; a sync whose heartbeat stops is failed after PIPELINE_HEARTBEAT_TIMEOUT and retried.

Terminal window
helm upgrade synclet oci://ghcr.io/synclet-io/charts/synclet \
--version <chart version> \
-f values.yaml \
--namespace synclet

The chart’s appVersion is the Synclet version it deploys; image.tag overrides it. The JWT secret, encryption key, internal API token and PostgreSQL password the chart generated on install are read back from <fullname>-secrets and kept. Pass your values file with -f on every upgrade: --reuse-values carries the previous release’s defaults over.

The Compose file pins the image tag. To upgrade, update the checkout and recreate the containers:

Terminal window
git pull
docker compose up -d

If you keep your own copy of docker-compose.yml, change its x-synclet-image tag instead. Your .env is not tracked and stays as it is.

Stop Synclet, replace the binary with the one from the release, run synclet migrate up, and start it again.

Breaking and operator-visible changes, newest first. Versions not listed need nothing beyond the steps above.

  • Registration is off by default. AUTH_REGISTRATION_ENABLED (auth.registrationEnabled in the chart) defaults to false; once an account exists, new email/password sign-ups are refused. Set it to true to keep sign-up open.
  • OIDC links to an existing account only for a verified email. A first OIDC login whose email matches an existing account links to it only when the ID token carries email_verified: true, whatever ALLOWED_DOMAINS is; otherwise it fails. Configure the provider to send email_verified.
  • Auth rate limits are shared by all replicas and keyed per client. They live in the database, and the chart’s rateLimit.trustedProxies defaults to the private ranges, so behind an ingress each client has its own limit. The login lockout now applies to one email from one client IP, so failures from one client no longer lock the account for everyone.
  • Runtime configs no longer take service_account_name. Every connector pod runs under the instance-wide PIPELINE_RUNTIME_SERVICE_ACCOUNT_NAME (pipeline.serviceAccount in the chart). synclet migrate up strips the key from stored runtime configs, and saving a runtime config that still sets it fails as an unknown key. A connector that relied on its own account for cloud or cluster permissions needs the instance-wide account to carry them.
  • Runtime configs no longer take docker_volumes. A connector container reaches host files only under /local, which the Docker executor mounts from DOCKER_EXECUTOR_LOCAL_ROOT (see files written by destinations). synclet migrate up strips the key from stored runtime configs, and saving a runtime config that still sets it fails as an unknown key. Move files a connector read from or wrote to a per-entity volume under the local root and point the connector’s config at /local.
  • Executors need an owner ID. A Docker or Kubernetes executor, standalone or inside synclet server, no longer defaults its owner ID to the hostname: without DOCKER_EXECUTOR_OWNER_ID (or K8S_EXECUTOR_OWNER_ID / K8S_EXECUTOR_OWNER_ID_PREFIX) it does not start (see owner IDs). The Compose file and the chart set one. Containers and Jobs an earlier version left under its hostname are not cleaned up when the new ID differs; once no sync is running, find them with docker ps -a --filter label=synclet.io/owner=<hostname> and remove them. A release with k8s.ownerId set now labels the Jobs and Secrets of each executor replica <ownerId>-<n>; once no job of the old pods runs, remove those left under the bare value: kubectl delete jobs,secrets -n <k8s.namespace> -l synclet.io/owner=<ownerId>.
  • Standalone runs one server pod; distributed components get PDBs. In standalone mode the chart no longer renders with server.replicaCount above 1 or server.pdb.enabled: true; to run several replicas, switch to mode: distributed. In distributed mode the server, jobs and executor each get a PodDisruptionBudget with maxUnavailable: 1 when they run more than one replica; set <component>.pdb.enabled: false to opt out. A release upgraded with --reuse-values keeps the old server.pdb.enabled: false default, so its server gets no PDB until that value is unset.
  • The executor is a StatefulSet. In distributed mode, delete the old Deployment before upgrading. Helm cannot turn a Deployment into a StatefulSet:

    Terminal window
    kubectl delete deployment <fullname>-executor -n <namespace>
    helm upgrade synclet oci://ghcr.io/synclet-io/charts/synclet --version 0.4.0 -f values.yaml -n <namespace>

    Syncs already running keep their pods, which report to the server directly.

  • executor.strategy is now executor.updateStrategy. It takes a StatefulSet update strategy, type: RollingUpdate or OnDelete, without maxSurge. A values file that still sets executor.strategy fails to render. The old chart’s default, carried over by --reuse-values, is tolerated.

  • Kubernetes owner label. The Kubernetes executor stamps synclet.io/owner on its Jobs and Secrets and cleans up only its own (see owner IDs). Jobs and Secrets created by earlier versions carry no owner label, and no executor removes them. Once no sync is running, delete them by hand:

    Terminal window
    kubectl delete jobs,secrets -n <k8s.namespace> -l 'synclet.io/sync-job,!synclet.io/owner'
    kubectl delete jobs,secrets -n <k8s.namespace> -l 'synclet.io/task,!synclet.io/owner'
  • Connector pods get no Kubernetes API token unless a connector service account is created or named (pipeline.serviceAccount or pipeline.resources.serviceAccountName). A connector that called the Kubernetes API needs one of those now.

  • Executors run without the database. synclet docker-executor and synclet k8s-executor need EXECUTOR_API_URL and EXECUTOR_API_TOKEN. The server needs the same token as PIPELINE_EXECUTOR_API_TOKEN. An executor drops DB_DSN and the other control-plane variables from its environment. The Helm chart wires all of this.
  • The executor commands lost --standalone. Use synclet server --standalone for a single process.
  • Docker owner label. The Docker executor stamps synclet.io/owner on its containers and cleans up only its own. Containers left by earlier versions (labelled synclet.io/managed=true without synclet.io/owner) are not removed; remove them by hand once no sync is running. Give each executor that shares a Docker daemon its own DOCKER_EXECUTOR_OWNER_ID.
  • Health probes moved. /live and /ready are served on the internal port (8081). Images up to 0.4.0 serve only /health on the public port. The chart’s probes default to the new paths. To run an old image with a newer chart, see Kubernetes: health checks.
  • Secrets are required and validated. Outside local development (ENVIRONMENT set to anything but development, or in a container) the server exits when AUTH_JWT_SECRET or SECRET_ENCRYPTION_KEY is missing. AUTH_JWT_SECRET must be at least 32 bytes and SECRET_ENCRYPTION_KEY a base64-encoded 32-byte key. Earlier versions generated a missing encryption key and stored it in <UserConfigDir>/synclet/encryption.key of the process’s user. An installation that relied on that must copy the file’s content into SECRET_ENCRYPTION_KEY before upgrading, or its stored credentials cannot be decrypted.
  • The image runs as a non-root user. A container that starts connectors through the host’s docker.sock needs --user 0:0 (or a group that owns the socket); see Docker.
  • synclet migrate down needs --module or --all, and --yes outside development.
  • The chart waits for PostgreSQL and runs migrate up before the jobs worker and executor start.

Synclet 0.5.1 adds a catch-up migration that creates objects missing on databases created by early versions, so upgrade older installations to 0.5.1 or later in one step rather than stopping at 0.5.0.

Airbyte is a trademark of Airbyte, Inc. Synclet is not affiliated with, endorsed by or sponsored by Airbyte, Inc. Connector images keep their own licenses: see Connector licenses.