Tags: Relational databasesDesktopCommand line
You have one list that matters and a call booked to get SPSync running against it. Maybe it is the Contracts list that finance reports on every month, or the Service Requests list behind a Power BI dashboard that has started timing out. Before anyone installs anything, someone on your side will ask where this thing is going to run. The analyst wants it on their laptop by Friday. The infrastructure lead would prefer a server they already patch and monitor. Your security team may want to know whether any of it can live inside your own Azure subscription.
All three answers are available, and you do not have to get the choice right first time. SPSync comes as a desktop app, a command line and a managed application in your own Azure, and all three run the same replication engine against the same destinations. What differs is who runs it, where its settings and sync state are kept, what triggers each run and how a licence counts it. Once you know those four things you can pick a starting point and see what a later move would involve.
SPSync desktop app vs command line vs Azure
| Desktop app | Command line | SPSync in your Azure | |
|---|---|---|---|
| Who runs it | One person, on their own Mac or Windows PC | Whoever owns the server, container or CI runner | A deployment in your subscription that we set up with you |
| Where it is configured | Screens in the app | A YAML file you can commit to git | The deployment’s own screens |
| What schedules it | The app, or its background service with the window closed | Your scheduler: cron, Task Scheduler, launchd, GitHub Actions, Azure DevOps or Airflow | The deployment |
| How it is licensed | One seat per machine, per target family | One seat per machine, per target family | Per deployment, per target family |
What the table cannot show is how much is shared. The editions differ in who presses the button and where the configuration sits. What arrives in your database does not change.
What stays the same in every edition
Every edition reads SharePoint through Microsoft Graph with the permissions you grant and
never writes back to SharePoint. The first run against a list is a full load, and every run
after that reads only what changed, keyed on SharePoint’s change tokens. A list becomes a
table with sp_item_id as its primary key. A lookup column arrives as a {col}_id and a
{col}_value, a person column as a user id that joins to a shared sp_users table, and a
multi-value column as a child table with one row per value. Deleted items are kept with an
sp_deleted_at timestamp by default, so last month’s figures still add up after someone
tidies the list. The schema reference lists every column type
and what it becomes.
Schema changes behave the same way too. A new column in SharePoint appears as a new column in the table, and a column you remove from the list stays in the table with its history. A reconcile pass compares every row with SharePoint on its own schedule, weekly by default and configurable per replication. You run it as a QA check that the two sides match, and it is how a replica catches up after an outage on your own server or at Microsoft 365.
Because of all that, a Power BI model or an internal app does not care which edition filled its tables. That is the property you rely on if you start small on one edition and move to another later.
There are two small differences, and both favour the command line. Hard deletes, where a
deleted SharePoint item’s row is removed from the table entirely, are a deletes: hard
setting in the command-line tool’s YAML; desktop and Azure runs always soft-delete. An
on-demand reconcile is also a command-line action (spsync reconcile). In the desktop app
and the Azure edition, reconcile runs on its schedule.
Running SharePoint sync from the desktop app
The desktop app runs on Apple Silicon Macs and on Windows 10 and 11 on x64. You sign in with your Microsoft account, find the site by name or paste its URL, tick the lists you want and choose a destination such as SQL Server, Azure SQL, Postgres or Supabase. The connection test sits on the same screen. With delegated sign-in, SPSync sees only the sites you can already open, so most people need nothing from IT to start. If your tenant requires admin consent for apps, or you later want unattended app permissions, the first-run wizard writes a one-page pack your admin can approve site by site with Sites.Selected. The admin permissions guide explains both routes.
Scheduling lives inside the app. Each replication shows its schedule, its last and next run, and pause, resume and run now controls, and every run shows the rows read and written for each list. A five-minute schedule is a sensible start for most reporting lists.
The question people ask next is what happens when the laptop lid closes. Turn on Keep syncing in the background in Settings and SPSync registers a per-user background service: a launchd agent on macOS, a Scheduled Task on Windows. It needs no admin rights, and scheduled syncs carry on with the window closed. With the setting off, syncs run while the app is open. A laptop that is switched off leaves the replica where it was, and the next run picks up every change made since, because the delta is keyed on SharePoint’s own change tokens.
The desktop app keeps its configuration on your machine, and rows go straight from SharePoint to the database you chose. That works well for an analyst proving the idea on one list, a developer who wants a table under an internal app, or a one-off migration. The trade-off is plain. A replication that depends on one person’s laptop being awake is fine for a team report and wrong for something a whole department relies on at 7am. When the replication starts to matter to more people than the one who set it up, the command line or the Azure edition is where it should go. Today’s desktop builds may also show an unsigned-app warning on first launch, which your IT team may want to know about before the call.
The desktop app page has the screens.
Scheduling SharePoint sync from the command line
The command line is the same engine driven by a YAML file. spsync export-config writes
that file from a site URL and the list names, and you commit it. A reviewer can see which
lists will replicate and to where, and the file holds no secrets: connection strings and
the licence key are environment variable names that are resolved when the job runs.
The biggest difference from the desktop app is that spsync run never loops or sleeps.
Each invocation does one sync round, so your own scheduler decides the cadence. On Linux
that is cron or a systemd timer, on Windows it is Task Scheduler, and on a Mac it is
launchd. In a pipeline it is a scheduled GitHub Actions workflow, an Azure DevOps pipeline
or an Airflow task. The exit code tells the scheduler whether the round succeeded, and the
output lists the rows read, inserted, updated and soft-deleted for each list.
If you set no interval, spsync doctor works one out from your permission mode and the
tenant’s request budget: 5 minutes with delegated sign-in and 1 minute with app-only
permissions, with 30 seconds as the floor. You can pin your own interval in the YAML
instead. Point your scheduler at the same number so that the schedule you configured is the
one that runs.
Two practical points catch people out. Hosted CI runners do not have SPSync installed, so a GitHub Actions or Azure DevOps job needs a self-hosted runner or agent where it is. Only one round runs per replication and destination at a time on a machine, and a second invocation that overlaps is refused with its own exit code and writes nothing. Two separate machines pointed at the same replication are not coordinated, so run each replication from one place.
On a server you will want app permissions: an app registration with Sites.Selected granted per site, signing in with a certificate or client secret taken from the environment. The command line runs on macOS, Windows and Linux, and there is no packaged installer for it, so we install it with you on the call. The command line page lists every command, and CLI automation has the cron, Task Scheduler and pipeline recipes.
The command line is a good fit for a data engineering team that wants the replication in the same repository as the dbt models that read it, or an IT team with a server it already runs scheduled jobs on. If nobody on your side wants to own a scheduler, it will feel like extra work, and the desktop app or the Azure edition will fit better.
SPSync in your own Azure subscription
SPSync in your Azure, a managed application for your own subscription, is deployed with you on a call while the Marketplace listing is prepared.
The deployment goes into a subscription and resource group you choose. You sign in with your own Entra app registration, so the conditional access policies you already have apply to it. When your network requires it, the deployment reaches your database over a private endpoint inside your own virtual network. Its connections, schedules and run history are held inside your subscription; the deployment’s own secrets are kept in a Key Vault there, and destination credentials in the deployment’s own database, also in your subscription. When a new version is ready, we upgrade the deployment with you.
Scheduling belongs to the deployment, much as it belongs to the app on the desktop, except that no laptop is involved. It meters Graph resource units and honours Microsoft’s Retry-After responses, and reconcile runs weekly by default, configurable per replication.
This is the edition for a team that wants nothing running on a laptop and cannot accept a vendor operating the infrastructure. It is also the right home for a Copilot Studio or Azure OpenAI project that has to stay inside the tenant, because the deployment can fill Azure SQL or Azure AI Search from your lists without the data leaving your subscription. The cost is that you pay for the Azure resources it uses, and setting it up takes a call with us. The SPSync in your Azure page has the deployment diagram.
Where replication state and secrets live
On the desktop app, the replication settings are stored locally on your machine, and the data itself goes from SharePoint to your destination with nothing in between. Activating a licence stores an activation token in the operating system’s keychain, or in a file only your user can read when no keychain is available.
On the command line, the replication definition is the YAML file, wherever you keep it, usually in git. Secrets stay in whatever secret store your scheduler already provides: GitHub Actions secrets, an Azure DevOps variable group, a systemd environment file or a Windows environment variable. The licence activation is held the same way as on the desktop.
In the Azure edition, everything sits in your subscription: the deployment, its configuration and run history, its Key Vault and the destination credentials. We never see your data or your credentials.
In all three, the replicated rows are in your database and nowhere else. SharePoint item permissions are not copied into the replica, so the database roles and row-level security you grant decide who reads what.
How SPSync licensing works across editions
A licence counts two things: the machines SPSync runs on, and the families of destination it writes to. There are three families. Relational databases cover SQL Server, Azure SQL, PostgreSQL, Supabase, MySQL, Oracle and others. Warehouses and lakes cover DuckDB, Parquet, Delta Lake and their neighbours. Search and vector stores cover Azure AI Search, pgvector, Elasticsearch and the rest. Every destination in a licensed family is included, and lists, items and sites are unlimited.
The desktop app and the command line take the same machine-bound licence key. A laptop running the desktop app is one seat, and a server running the command line is another. You can deactivate a machine and move its seat at any time, and a machine that cannot reach the activation service can be given an offline key on request. The Azure edition is licensed per deployment and target family on the same annual terms. Every licence runs for a year with Standard Support included.
We do not publish a price list. You book a call, tell us the targets and the number of machines, and you get a quote within one business day. How licensing works has a worked example with a laptop, a server and two relational destinations.
Moving a replication from one edition to another
Because the tables are identical, moving is mostly a matter of setting the replication up
again in the new place against the same destination. To move from the desktop app to the
command line, spsync export-config writes the YAML from the site URL and the list names
you already use. To move to the Azure edition, the replication is set up in the deployment
with the same lists and the same destination. Either way the tables carry on as they are,
and the reports built on them keep working.
Stop the schedule in the old place once the new one is running. Two editions syncing the same replication into the same destination are not coordinated with each other.
Which edition should your team start with?
If one person owns the report and the list, start on the desktop app. You will see rows in your database on the first call, and nothing about that choice locks you in. If the replication belongs to a team that already runs a server, a container platform or a CI system, start on the command line and keep the YAML next to the code that reads the tables. If your security team wants the whole workload inside your own subscription, or the replica is feeding a Copilot Studio or Azure OpenAI project in the tenant, ask for the Azure edition on the call.
You can also run two of them side by side for different replications. An analyst proves the schema on the desktop app while the infrastructure lead prepares a server for the command line. That is two machines and one family on one licence. When you are ready, book a call and bring the list you have in mind.