Last updated
One way: SharePoint stays the system of record, and SPSync keeps a read-only copy of your lists current in SQLite.
Status: Shipped · product: Included in every product
The simplest place to put a SharePoint list is a file. SQLite runs without a server and needs neither a connection string nor credentials of its own: SPSync writes one file at a path you choose, and you open it with DB Browser for SQLite, DuckDB, pandas or any language’s SQLite driver.
What the file holds
A course booking list with a Course lookup, an Attendee person column, a Booked on
date and a multi-choice Dietary needs column becomes a train_bookings table keyed on
the SharePoint item ID. course_id and course_value carry the lookup.
attendee_user_id lines up with the shared sp_users table. train_bookings__dietary_needs
has one row per booking and need, so a query joins it with plain SQL and never splits a
delimited string.
Deleted items keep their row with sp_deleted_at set. New SharePoint columns appear on
the next run, removed ones stay in the file, and a retyped column keeps its history while
a _v2 column takes the new type.
| Title | Client lookup | Tags multi-choice | Owner person | Due |
|---|---|---|---|---|
| Riverside | Acme Ltd | Design; Build | Ada Lovelace | 2026-11-30 |
| Harbour | Borealis plc | Build | Alan Turing | 2027-02-14 |
then sync
- id
- title
- client_id → clients.id
- owner_id → sp_users.id
- due
- is_deleted soft delete
- sp_modified
- id
- title
- …
- project_id
- tag
One row per value: Riverside has two.
- id
- display_name
One users table shared by every list.
Three SQLite habits to know
SQLite declares types without enforcing them, and two of SPSync’s choices follow from that.
- Dates are text with a space separator. A datetime is stored as
2026-01-01 00:00:00.000000in UTC, with noTand no time zone suffix. Compare with SQLite’s owndatetime()andstrftime()functions, or with a literal in the same shape, since'2026-01-01T00:00:00Z'will not match. - Currency is not exact. Currency columns are declared
NUMERIC(38, 9), but SQLite stores most values as floating point. Round, or compare with a tolerance, in money-sensitive reports. - WAL mode is on. SPSync switches the file to WAL journaling, so readers keep reading while a run writes. Keep SPSync as the only writer.
Ways people use the file
Behind a small tool or script. A notebook or local utility that called Graph for reference data reads the file instead, with no network round trip; see a read replica for internal apps.
Desktop analysis. An analyst gets a relational schema in DB Browser for SQLite, R or Python, and stops exporting CSVs by hand; see reporting and analytics on SharePoint list data.
A queryable backup. Because deleted items stay on record, a copy of the file is a point-in-time backup of the list; see continuous backup and history of lists.
Evaluation. SQLite needs no decisions up front, so it shows the schema SPSync generates before you choose Postgres, SQL Server or a warehouse.
Setting it up
- Sign in with delegated access. A scheduled sync on a server needs
Sites.Selectedapp permissions, which an admin approves per site. - Choose a path for the file. SPSync creates it on the first run.
- Choose the lists or a whole site. The first run creates one table per list, child
tables for multi-value columns and
sp_users. - Set how often it runs, every few minutes up to hourly.
- Open the file in the tool you prefer.
The file needs to sit where its readers can open it, so most SQLite syncs run from the desktop app on the machine that uses the file, or from the command line as a build step that regenerates it.
Watch it run
Chapters are in the video's description.
Watch the walkthrough: the Northwind Analytics demo lists in SharePoint, connecting to Microsoft 365 in the desktop app, picking lists, the run into a local SQLite file, and the replicated tables and rows.
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.
Frequently asked questions
Do I need a database server to use SQLite as a destination?
No. SPSync writes one SQLite file on disk, so there is nothing to install or run apart from SPSync, which makes it the quickest way to see first rows.
Can I query the file while a sync is writing to it?
Yes. SPSync opens the file in WAL mode, so a reader such as DB Browser for SQLite, DuckDB or a script is not blocked while the next run writes.
How large a list can one SQLite file hold?
SPSync is tested to 10,000 items on a live tenant and to 1,000,000 on a synthetic Graph, and SQLite copes well with large single files. For many users writing or reading at once, a server database such as Postgres or SQL Server is the better choice.
Is there a free trial for the SQLite destination?
SQLite is included in every SPSync product, so there is no separate trial to start. Get in touch if you would like a walkthrough first.
Does SPSync create foreign key constraints?
No. Each table gets a primary key, and every lookup or person column gets a key column to join on, such as client_id or owner_user_id. No constraint ties those columns together, so rows can arrive in any order without failing a run. Once the schema has settled you can add constraints yourself.
Talk to us about SQLite (local file, desktop analytics)
SPSync is licensed per installation and per target family, with Standard Support included. Tell us which targets you need and how many machines, and we will size it with you. See how licensing works.
Set it up
Sign in to SharePoint with the SharePoint connection guide, then follow the SQLite setup guide to create the database user and open the connection for SQLite (local file, desktop analytics). If the connection test fails, the troubleshooting guide lists the errors people hit and what fixes them.
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 sqlite --prefix sqlite --destination-kind sqlite --connection-string-env SPSYNC_DB_CONNECTION --dataset-name sqlite --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: sqlite
prefix: sqlite
auth:
mode: delegated
client_id: 00000000-0000-0000-0000-000000000000
tenant_id: common
destination:
kind: sqlite
connection_string_env: SPSYNC_DB_CONNECTION
dataset_name: sqlite
scopes:
- site_url: https://contoso.sharepoint.com/sites/example
mode: entire_site
reconcile_interval_days: 7
create_reporting_views: false
Cron (SQLite 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.