Backup and Restore
Synclet keeps all of its state in PostgreSQL. The server, jobs and executor processes hold nothing that a restart would lose, so a backup is the database plus the key that decrypts the credentials stored in it.
What to back up
Section titled “What to back up”| What | Why |
|---|---|
| The PostgreSQL database | Everything: users, workspaces and members, sources, destinations and connections, stream configuration, sync state (cursors), jobs and their logs, notification settings, API keys, the audit log. Each module has its own schema (auth, workspace, pipeline, secret, notify, audit); dump the whole database, not single schemas. |
SECRET_ENCRYPTION_KEY | Connector credentials are stored AES-encrypted in the secret schema. A dump restored without the key that encrypted them is unusable: no source or destination can authenticate. |
SECRET_ENCRYPTION_KEY_PREVIOUS, during a key rotation | Rotation is lazy: a credential is re-encrypted with the new key only when it is next read. A backup taken while both keys are set can hold credentials under either, so keep both with it. |
The log archive bucket or directory, if PIPELINE_LOG_ARCHIVE_BACKEND is not none | The logs of finished jobs. Synclet runs without them, but the UI can no longer show logs it cannot read. |
AUTH_JWT_SECRET needs no backup: a new one only signs everyone out.
Where the encryption key comes from
Section titled “Where the encryption key comes from”Synclet reads the key from the SECRET_ENCRYPTION_KEY environment variable: a base64-encoded 32-byte key. Back up the value from wherever you set it (your .env, secret manager or Kubernetes Secret).
-
Helm. The key is
encryption.key, theencryption-keykey ofencryption.existingSecret, or the Vault path whenvso.enabledis set. When none is set, the chart generates one on first install and stores it in<fullname>-secrets:Terminal window kubectl get secret <fullname>-secrets -n <namespace> \-o jsonpath='{.data.encryption-key}' | base64 -dThe chart finds the generated key again on upgrade with a Helm
lookup, which returns nothing underhelm templateand some GitOps tools. Set the key yourself there, throughencryption.keyorencryption.existingSecret. -
Docker Compose.
.env.composeholds a public default key, overridden bySECRET_ENCRYPTION_KEYin.env. Synclet warns at startup while the public default is in use. -
Binary in local development. When
ENVIRONMENTis unset ordevelopmentand Synclet is not in a container, a missing key is generated once and stored in<UserConfigDir>/synclet/encryption.key(~/.config/synclet/encryption.keyon Linux,~/Library/Application Support/synclet/encryption.keyon macOS). Back up that file. Anywhere else Synclet refuses to start without the variable.
Store the key apart from the database backups, so that one leaked backup does not expose both.
Config export is not a backup
Section titled “Config export is not a backup”Settings > General > Export Configuration writes a workspace’s sources, destinations and connections to YAML. It is meant for moving a setup between installations (see Settings: Config Export & Import), and it leaves out most of what a restore needs:
- Config keys that look like secrets (containing
password,secret,token,key,credentialorprivate) are exported as***REDACTED***. New sources and destinations created by an import need their credentials entered again. - Connections carry only their source, destination, schedule, max attempts, enabled flag and tags. Stream selection, sync modes, transforms, namespace settings and connection names are not exported, and an import creates new connections with defaults.
- Sync state is not exported, so imported incremental connections start from scratch.
- Users, members, roles, notification settings, webhooks, API keys, job history and the audit log are not exported.
Back up the database.
Backing up the database
Section titled “Backing up the database”Any PostgreSQL backup method works. Synclet needs nothing special from it.
pg_dump
Section titled “pg_dump”pg_dump -Fc "$DB_DSN" > synclet_$(date +%Y%m%d).dumpA dump is consistent at the moment it starts, without stopping Synclet. Schedule it daily at least, and copy it off the database host.
Managed PostgreSQL
Section titled “Managed PostgreSQL”On RDS, Cloud SQL, Azure Database for PostgreSQL and similar services, turn on automated backups with point-in-time recovery (PITR). PITR restores the database to any moment within the retention window, which a nightly dump cannot.
CloudNativePG
Section titled “CloudNativePG”On Kubernetes, CloudNativePG runs PostgreSQL with continuous WAL archiving and base backups to S3, GCS or Azure Blob. Recent releases do this through the Barman Cloud plugin:
apiVersion: barmancloud.cnpg.io/v1kind: ObjectStoremetadata: name: synclet-backupsspec: configuration: destinationPath: s3://synclet-backups/cnpg s3Credentials: inheritFromIAMRole: true # IRSA; or accessKeyId/secretAccessKey from a Secret wal: compression: gzip retentionPolicy: "30d"---apiVersion: postgresql.cnpg.io/v1kind: Clustermetadata: name: synclet-dbspec: instances: 2 storage: size: 20Gi plugins: - name: barman-cloud.cloudnative-pg.io isWALArchiver: true parameters: barmanObjectName: synclet-backups---apiVersion: postgresql.cnpg.io/v1kind: ScheduledBackupmetadata: name: synclet-db-dailyspec: schedule: "0 0 3 * * *" # seconds field first cluster: name: synclet-db method: plugin pluginConfiguration: name: barman-cloud.cloudnative-pg.ioFor GCS, use destinationPath: gs://<bucket>/cnpg with googleCredentials instead of s3Credentials. Point the chart at the cluster’s <cluster>-rw Service with postgresql.enabled: false and externalDatabase.*. CloudNativePG restores into a new Cluster whose bootstrap.recovery names the object store, optionally with a recoveryTarget time.
The chart’s bundled PostgreSQL (postgresql.enabled: true) is meant for development and testing and has no backups of its own.
Restoring
Section titled “Restoring”-
Stop Synclet. Stop every process that writes to the database: the server, the jobs worker and the executors. With Helm, scale them to zero:
Terminal window kubectl scale deployment <fullname>-server <fullname>-jobs --replicas=0 -n <namespace>kubectl scale statefulset <fullname>-executor --replicas=0 -n <namespace>In standalone mode only
<fullname>-serverexists. With Compose,docker compose stop synclet. -
Restore the database into an empty database:
Terminal window pg_restore --no-owner -d "$DB_DSN" synclet_20260401.dumpOr restore a managed snapshot, a PITR target or a CloudNativePG recovery cluster, and point
DB_DSNat it. -
Set the same encryption key the backup was taken with in
SECRET_ENCRYPTION_KEY, andSECRET_ENCRYPTION_KEY_PREVIOUSif a rotation was in progress. -
Apply migrations. Run the Synclet version you are about to start, the same as the backup’s or newer:
Terminal window synclet migrate upThe Helm chart runs it in the
migrateinit container of the server and jobs pods, and the Compose file in itsmigrateservice, so starting them is enough. -
Start Synclet: the server and jobs first, then the executors. Check
/readyon the internal port, then test the connection of a source with stored credentials: with the wrong key, Synclet cannot decrypt them and the test fails.
Jobs that were running when the backup was taken come back as starting or running with an old heartbeat. The heartbeat watchdog fails them after PIPELINE_HEARTBEAT_TIMEOUT and schedules a retry while attempts remain.
Destination data written after the backup stays in the destination. Incremental connections resume from the cursor stored in the backup and read those records again: append-mode streams can end up with duplicates, deduplicated streams do not.
See also
Section titled “See also”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.