These are the seven steps from a SharePoint list to a SQL Server table that stays current: connect, review the list, pick it, connect SQL Server, run the first sync, schedule it and watch it run. Each one is shown three ways in the tabs, for the desktop app, SPSync in your Azure and the command line. By the end, lookups are id columns you can join on, multi-value columns are child tables and deleted items are kept.
A schedule as well as a first copy
A one-off export or a script gets the list into SQL Server once. Keeping it right through schema changes, deletions and throttling is a different job, and the last three steps cover it: the schedule, the reconcile and the run history.
The schema you end up with
Each list becomes a table keyed on the SharePoint item id. A single-value lookup becomes an id column pointing at the target list’s table, and a multi-value lookup or choice becomes a child table with one row per value per item. If a SharePoint column changes type, say a number becoming text, SPSync adds a column for the new type and leaves the old values as they were. A column deleted in SharePoint stays in the table, so a report built on it keeps running.
When the same list exists on several sites, SPSync can gather them into one table, so a report reads one set of rows in place of several exports joined by hand.
Other destinations
SQL Server is one of many destinations, alongside other relational databases, warehouses, lakes, search indexes and vector stores. The same lists can go to several of them, one replication each. If the destination you need is missing, get in touch.
Connect to SharePoint
What you see: The site picker asking for a URL or a site name, then the permissions wizard's one-page pack before anything is granted.
Why it matters: An interactive setup uses the signed-in account's own access, and an unattended schedule under Sites.Selected reaches only the sites you name.
What it replaces: A tenant-wide Sites.Read.All grant requested for a single list.
See what you are replicating
What you see: Every list and library on the site, with columns and item counts, as soon as you pick a site.
Why it matters: The browser shows every column, including those a default view hides, so the schema holds no surprises on the first run.
What it replaces: Guessing a list's columns from the SharePoint UI, which only shows the columns a view happens to include.
Browse the site's lists and libraries, with column names, types and item counts shown next to SharePoint's own view.
List the site's lists and columns from the terminal before writing a config.
spsync discover lists --client-id $SPSYNC_CLIENT_ID --site-url https://contoso.sharepoint.com/sites/projects
Choose the list
What you see: Projects ticked on its own, several lists picked by name, or the whole site selected at once.
Why it matters: Syncing the whole site means a list created later on the same site is picked up on the next run, with nothing to edit by hand.
What it replaces: A config file that has to be edited every time a new list needs to be added to the same schedule.
Tick the list you want, or pick several by name.
Choose the whole site if the same list template exists on many sites.
Name the lists to sync when writing the config in the next step. Leave the flag off to sync the whole site.
Connect SQL Server
What you see: A connection string tested against the target database, with the schema preview showing every column, its type and which columns are lookups.
Why it matters: SPSync creates and maintains the tables from here, one table per list, so there is nothing to create by hand before the first run.
What it replaces: A hand-written CREATE TABLE script kept in step with SharePoint's own schema by hand.
Give SPSync a connection string for SQL Server or Azure SQL and test the connection before committing to it.
Check the schema preview: every column, its type, and which columns are lookups, before anything runs.
Write the replication config for the list against SQL Server in one file.
spsync export-config --output projects.yaml --pipeline-name projects --prefix sp --destination-kind mssql --connection-string-env SPSYNC_DB_CONNECTION --dataset-name projects --client-id $SPSYNC_CLIENT_ID --site-url https://contoso.sharepoint.com/sites/projects --lists-by-name Projects,Tasks,Departments --create-reporting-viewsCheck the ODBC driver, the SharePoint permissions and the SQL Server connection before the first run.
spsync doctor projects.yaml
Run the first sync
What you see: Every row written into the schema from the previous step, with lookups and multi-value columns already resolved.
Why it matters: Only the first run reads every row; from then on each run is a small delta that finishes in minutes.
What it replaces: A one-off export to a spreadsheet, loaded by hand, that is already stale the moment it finishes.
Click Run now and watch the row counts arrive, table by table.
Run the replication. The terminal shows the full load first, then delta counts on later runs.
spsync run projects.yaml
Keep it in sync automatically
What you see: A schedule ticking over in minutes, and a reconcile running behind it (weekly by default).
Why it matters: Short delta runs keep SQL Server minutes behind SharePoint, and the reconcile (weekly by default) confirms the two still match.
What it replaces: A cron job or a flow someone has to remember to check, with no built-in retry or backoff for throttling.
Set the schedule, for example every five minutes, so the sync checks for changes automatically.
Drive the schedule from a cron job, a scheduled task or a CI pipeline. The config already has the full reconcile interval set.
spsync reconcile projects.yaml
Watch it run and report on it
What you see: Rows read and written for every run in one place, with any error named by the list and the column it happened on.
Why it matters: When a run fails, the message points at a list and a column, which saves tracing a row number back through the logs.
What it replaces: Alerting and logging someone has to wire up separately around a hand-written script.
Open the run history to see rows read and written per list, and any error named by list and column.
Tail the latest run's log output, one event per line.
spsync logs tail