checkpoint schema in your sync function to enable checkpoint support. If you are migrating from nango.lastSyncDate, see the migration guide.
Why checkpointing matters
Without checkpoints, every sync run fetches the entire dataset from the external API. This works for small datasets, but quickly becomes unsustainable as data grows. Consider a Salesforce account with 500,000 contacts syncing every 15 minutes: without checkpoints, each run re-fetches all 500,000 records even if only a handful changed — consuming orders of magnitude more API calls, compute time, and memory than necessary. Checkpoints solve this by tracking how far your sync has progressed. The benefits compound:- Performance — Only fetch what changed. A 15-minute incremental sync processes minutes of changes, not years of history.
- Resilience — If a sync fails mid-execution, the next run resumes from the last checkpoint instead of restarting from scratch.
- Lower costs — Less compute time on Nango, fewer API calls against the external API’s rate limits, and lower bandwidth consumption.
- Higher freshness — Faster syncs mean you can run them more frequently, keeping your data closer to real-time.
Function interruption and resumption
Nango reserves the right to cap the duration of a function execution. When an execution reaches the limit, Nango interrupts it gracefully and schedules the next execution to start immediately. Checkpoints are what make this seamless: the next execution should callgetCheckpoint() and resumes from where the previous one stopped. Without checkpoints, each execution starts from scratch, meaning any function that takes longer than the execution cap will loop indefinitely without ever completing.
The interrupt-and-resume flow:
- Sync runs, processes records, saves a checkpoint after each page.
- Nango interrupts the sync gracefully when the execution cap is reached (ie: after the current
saveCheckpoint()call completes). - The next execution starts immediately, calls
getCheckpoint(), and continues from that point. - This repeats until the sync finishes naturally.
How checkpoints work
A checkpoint is a small payload, defined by a schema you control, that your sync saves after processing each batch of data. On the next execution, the sync reads the checkpoint to know where it left off. The typical flow is:- Read the current checkpoint with
nango.getCheckpoint()(returnsnullon first run). - Fetch a page of data from the external API, starting from the checkpoint.
- Save the records to Nango’s cache with
nango.batchSave(). - Save a new checkpoint with
nango.saveCheckpoint(). - Repeat until there is no more data.
Defining a checkpoint schema
You define your checkpoint schema in thecreateSync() declaration using Zod, just like your data models. The schema describes the shape of the progress marker your sync will save.
Most commonly, the checkpoint is a timestamp indicating how far you’ve synced:
Implementing an incremental sync with checkpoints
Here is a complete example syncing Salesforce contacts incrementally:The first sync run
Even with checkpoints, the very first execution has no previous progress to resume from —getCheckpoint() returns null. This initial run fetches the entire historical dataset and is inherently more resource-intensive than subsequent runs.
One strategy to manage this is to limit the backfill window. For example, if you are syncing a Notion workspace, you might only fetch pages modified in the last three months, assuming older pages are less relevant:
Implementing a full sync with checkpoints
Not every sync can be incremental. Some APIs don’t support filtering by modification date, so you must fetch all records on every run. Such syncs can still benefit from checkpoints for resilience: if a run is interrupted mid-dataset, the next run resumes from the last page instead of starting over. CallclearCheckpoint() at the end of a successful run so the next scheduled run starts from the first page.
When to sync without checkpoints
For small datasets (e.g., a list of Slack users for an organization with fewer than 100 employees), a sync without checkpoint can be perfectly fine. As datasets grow, full syncs become unscalable — taking longer to run, triggering rate limits, and consuming more compute and memory. If your dataset has more than a few thousand records and the API supports pagination and/or filtering by date or cursor, use checkpoints.Checkpoints vs. cursors
Both checkpoints and cursors are markers of sync progress, but they track different relationships:
Both are important: checkpoints keep your sync efficient, and cursors keep your application’s data consumption efficient.
Re-syncing: resetting checkpoints and the cache
When you trigger a sync manually (from the UI or API), you can control whether to preserve or reset progress:
Leave both off for a standard incremental sync.
Use
reset: true when you want to re-fetch everything from the external API but preserve the cache for accurate change detection. This is useful when you suspect data may have been missed.
Use reset: true with emptyCache: true when you need to start from scratch — for example, after a breaking change to your data model.
Observability
Checkpoints are exposed in several places to help you monitor sync progress:- Sync webhooks — The sync completion webhook includes checkpoint information, so your application knows how far the sync has progressed.
- Sync status API — The GET /sync/status endpoint returns the current checkpoint for each sync, letting you check progress programmatically.
- Logs — Checkpoint-related details are visible in the Nango dashboard logs. (We are actively improving checkpoint visibility in the dashboard.)
Testing checkpoints locally
When developing locally with the Nango CLI, you can pass a checkpoint value todryrun to simulate resuming from a previous run: