Scriptable migrations: config in git, reviewed in PRs, run from CI, batched across many sites, re-runnable

Script SharePoint replications as YAML in git: reviewed in pull requests, run from CI, batched across many sites and safe to re-run.

Book a call

Book a call to talk through your use case, see further walkthroughs or demos, and set up a trial in your own environment.

Last updated

Most SharePoint replication tools are click-through wizards: every environment is set up by hand again, nothing is reviewable, and nothing runs unattended from CI.

Replicating the same twelve lists in a test tenant, then staging, then production, is three rounds of the same forty clicks in a wizard. Nothing can be reviewed before a run, no scheduler or CI pipeline can drive it without wrapping the GUI, and once the person who clicked moves on there is no record of what was chosen.

The whole replication in one file

SPSync works from the command line as well as the desktop. spsync export-config discovers the sites and lists you point it at and writes a ReplicationConfig YAML file. That one plain-text file describes the entire replication and means the same thing every time it runs, in every environment.

The file is safe to commit. Connection strings and the licence key are environment variable references, such as connection_string_env: SPSYNC_DB_CONNECTION, never literal secrets. Once it is in git, a change to the replication is reviewed in a pull request: a teammate sees which sites, lists and destination it touches before it runs anywhere.

Running it from CI

spsync doctor checks the ODBC driver, the Graph permissions and the destination connection before spsync run moves any data. A broken pipeline fails early with a clear message, before a half-finished sync can happen. The first run against a config is a full load and every run after it is a delta, so a retried CI job or a rescheduled trigger never writes a row twice.

Many sites at once

spsync export-config accepts --site-url more than once, and spsync batch create batch.yaml writes one config per site across a whole tenant’s worth of sites in a single command. Twelve lists in three tenants is three files, one per tenant, each reviewed once.

Scripting needs no separate edition: the command line works from the first command. The desktop app and SPSync in your Azure run the same engine behind a picker, which some people prefer day to day. This use case is the one the command line was built for: spsync run against a committed YAML file, safe to re-run from CI.

Desktop, Azure or command line

All three editions run the same engine, write the same tables and use the same licence key, so the choice comes down to who looks after the sync.

Desktop app

For macOS and Windows. Sign in with Microsoft, tick the lists, choose a database and sync from your own machine on the schedule you set. Delegated sign-in needs no admin unless your tenant requires admin consent for apps.

In your Azure

SPSync in your Azure, a managed application for your own subscription, is deployed with you on a call while the Marketplace listing is prepared. Once deployed it is always on, so the sync keeps running with every laptop closed.

Command line

Every replication is a YAML file you can review and commit. Run it from a server, a container or a CI pipeline, and re-run it safely any time.

Set it up

Ready to run this against your own site? The setup guide takes you from install to a first replication, and the SharePoint connection guide covers signing in.

Script it

Everything you can click, you can script. The CLI, YAML config and automation below reproduce this scenario exactly. See the CLI reference.

spsync auth login --client-id 00000000-0000-0000-0000-000000000000
spsync export-config --output replication.yaml --pipeline-name scriptable_migrations --prefix scriptable_migrations --destination-kind postgres --connection-string-env SPSYNC_DB_CONNECTION --dataset-name scriptable_migrations --client-id 00000000-0000-0000-0000-000000000000 --site-url https://contoso.sharepoint.com/sites/example --all-lists
spsync doctor replication.yaml
spsync run replication.yaml
pipeline_name: scriptable_migrations
prefix: scriptable_migrations
auth:
  mode: delegated
  client_id: 00000000-0000-0000-0000-000000000000
  tenant_id: common
destination:
  kind: postgres
  connection_string_env: SPSYNC_DB_CONNECTION
  dataset_name: scriptable_migrations
scopes:
  - site_url: https://contoso.sharepoint.com/sites/example
    mode: entire_site
reconcile_interval_days: 7
create_reporting_views: false

Cron (PostgreSQL nightly):

# every night at 02:00
0 2 * * * cd /opt/spsync && SPSYNC_DB_CONNECTION="$(cat /etc/spsync/db.env)" uv run spsync run replication.yaml >> /var/log/spsync/run.log 2>&1

GitHub Actions:

# .github/workflows/spsync-run.yml
name: SPSync
on:
  schedule:
    - cron: "0 2 * * *"
  workflow_dispatch: {}
jobs:
  run:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v3
      - run: uv sync
      - run: uv run spsync run replication.yaml
        env:
          SPSYNC_DB_CONNECTION: ${{ secrets.SPSYNC_DB_CONNECTION }}
          SPSYNC_LICENCE_KEY: ${{ secrets.SPSYNC_LICENCE_KEY }}

Azure DevOps:

# azure-pipelines.yml
schedules:
  - cron: "0 2 * * *"
    branches: { include: [main] }
    always: true
steps:
  - script: uv sync
  - script: uv run spsync run replication.yaml
    env:
      SPSYNC_DB_CONNECTION: $(SPSYNC_DB_CONNECTION)
      SPSYNC_LICENCE_KEY: $(SPSYNC_LICENCE_KEY)

Windows (PowerShell + Task Scheduler):

# Windows Task Scheduler action (see /docs/cli/automation/)
$env:SPSYNC_DB_CONNECTION = (Get-Content C:\spsync\db.env)
uv run spsync run C:\spsync\replication.yaml
schtasks /Create /SC DAILY /ST 02:00 /TN "SPSync" /TR "powershell -File C:\spsync\run.ps1"

macOS (launchd):

# ~/Library/LaunchAgents/io.spsync.run.plist, then: launchctl load ~/Library/LaunchAgents/io.spsync.run.plist

Secrets (licence key, connection strings) come from the environment, so never write them into the YAML. See scheduling and secrets.

Book a call

Book a call to talk through your use case, see further walkthroughs or demos, and set up a trial in your own environment.