[{"data":1,"prerenderedAt":1015},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fstreams\u002Fresumable-load":3},{"id":4,"title":5,"body":6,"description":1006,"extension":1007,"meta":1008,"navigation":1009,"path":1010,"redirect":1011,"seo":1012,"stem":1013,"__hash__":1014},"docs\u002Fdocs\u002Fstreams\u002Fresumable-load.md","Resumable Load",{"type":7,"value":8,"toc":994},"minimark",[9,13,17,26,29,51,54,59,62,90,93,97,196,199,203,214,217,221,228,254,257,261,264,318,321,327,331,337,412,415,429,436,443,447,458,505,512,522,527,537,736,873,884,888,894,914,917,921,924,938,941,958,962,990],[10,11,5],"h1",{"id":12},"resumable-load",[14,15,16],"p",{},"Resumable Load breaks an eligible table load into primary-key ranges and persists the boundary of each completed chunk. If the stream is interrupted mid-copy, the next start continues from the next incomplete chunk instead of re-reading rows that already made it to the target.",[14,18,19,20,25],{},"For a copy-paste lab that starts a Load stream, stops it after one completed chunk, and verifies resume on the next start, see ",[21,22,24],"a",{"href":23},"\u002Fdocs\u002Fstreams\u002Fresumable-load-walkthrough","Resumable Load Walkthrough",".",[14,27,28],{},"Under the hood, DBConvert Streams implements Resumable Load as resumable chunked snapshot copy. The same mechanism backs both supported load paths:",[30,31,32,40],"ul",{},[33,34,35,39],"li",{},[36,37,38],"strong",{},"Load mode"," — the whole run is one bounded load.",[33,41,42,45,46,50],{},[36,43,44],{},"Initial Load + CDC for MySQL sources"," — the bootstrap copy that runs before CDC apply takes over. See ",[21,47,49],{"href":48},"\u002Fdocs\u002Fstreams\u002Finitial-load-and-cdc","Initial Load + CDC"," for the surrounding lifecycle.",[14,52,53],{},"DBConvert Streams chooses this path automatically per table. There is no public enable\u002Fdisable flag.",[55,56,58],"h2",{"id":57},"when-the-chunked-path-is-used","When the chunked path is used",[14,60,61],{},"Tables are routed to the resumable chunked path when all of the following are true:",[30,63,64,67,70,77,87],{},[33,65,66],{},"the source is MySQL or PostgreSQL",[33,68,69],{},"the target is a MySQL or PostgreSQL database",[33,71,72,73],{},"the target write mode is ",[74,75,76],"code",{},"upsert",[33,78,79,80,83,84],{},"the schema policy is ",[74,81,82],{},"create_missing_only"," or ",[74,85,86],{},"validate_existing",[33,88,89],{},"the table has a single-column numeric primary key",[14,91,92],{},"Tables outside those rules stay on the plain snapshot path in the same run.",[55,94,96],{"id":95},"supported-engines-and-modes","Supported engines and modes",[98,99,100,119],"table",{},[101,102,103],"thead",{},[104,105,106,110,113,116],"tr",{},[107,108,109],"th",{},"Scenario",[107,111,112],{},"Source engines",[107,114,115],{},"Target engines",[107,117,118],{},"Status",[120,121,122,135,147,160,172,185],"tbody",{},[104,123,124,127,130,132],{},[125,126,38],"td",{},[125,128,129],{},"MySQL, PostgreSQL",[125,131,129],{},[125,133,134],{},"Auto when a table is eligible",[104,136,137,140,143,145],{},[125,138,139],{},"Initial Load + CDC — MySQL source",[125,141,142],{},"MySQL",[125,144,129],{},[125,146,134],{},[104,148,149,152,155,157],{},[125,150,151],{},"Initial Load + CDC — PostgreSQL source",[125,153,154],{},"PostgreSQL",[125,156,129],{},[125,158,159],{},"Plain bootstrap only",[104,161,162,165,167,169],{},[125,163,164],{},"Custom SQL queries",[125,166,129],{},[125,168,129],{},[125,170,171],{},"Plain snapshot path",[104,173,174,177,180,182],{},[125,175,176],{},"File \u002F S3 sources",[125,178,179],{},"—",[125,181,179],{},[125,183,184],{},"Not applicable",[104,186,187,190,192,194],{},[125,188,189],{},"Composite or non-numeric primary keys",[125,191,129],{},[125,193,129],{},[125,195,171],{},[14,197,198],{},"PostgreSQL CDC bootstrap still uses the non-resumable path. Its exported snapshot name is only valid while the replication-slot connection stays open, so a crash-resume cannot replay into the same source snapshot yet.",[55,200,202],{"id":201},"what-automatic-routing-means","What automatic routing means",[30,204,205,208,211],{},[33,206,207],{},"eligible tables use chunked resumable load with durable progress state",[33,209,210],{},"ineligible tables continue on the plain snapshot path in the same run",[33,212,213],{},"the saved stream configuration does not expose a separate resumable-snapshot option",[14,215,216],{},"This lets one run mix chunked and plain tables without changing the public API.",[55,218,220],{"id":219},"chunk-strategy","Chunk strategy",[14,222,223,224,227],{},"The chunking strategy is ",[74,225,226],{},"pk_range",":",[229,230,231,242,245,251],"ol",{},[33,232,233,234,237,238,241],{},"Preflight reads ",[74,235,236],{},"MIN(pk)"," and ",[74,239,240],{},"MAX(pk)"," per selected table.",[33,243,244],{},"The range is split into inclusive numeric chunks sized by an internal default.",[33,246,247,248,25],{},"Each chunk runs as ",[74,249,250],{},"SELECT … WHERE pk BETWEEN \u003Clower> AND \u003Cupper> ORDER BY pk",[33,252,253],{},"The chunk boundary is written to durable state after the target acknowledges the writes.",[14,255,256],{},"Chunks are processed sequentially per table. Row counts, bytes, and elapsed time keep flowing through the existing source and target table stats — the new state tracks only the copy boundary, not a second progress counter.",[55,258,260],{"id":259},"recovery-on-restart","Recovery on restart",[14,262,263],{},"On the next start, preflight reconciles the current config against the stored state:",[98,265,266,276],{},[101,267,268],{},[104,269,270,273],{},[107,271,272],{},"Outcome",[107,274,275],{},"What happens",[120,277,278,288,298,308],{},[104,279,280,285],{},[125,281,282],{},[74,283,284],{},"fresh",[125,286,287],{},"No prior state; plan ranges and start from chunk 0.",[104,289,290,295],{},[125,291,292],{},[74,293,294],{},"resume",[125,296,297],{},"State matches; continue from the next incomplete chunk.",[104,299,300,305],{},[125,301,302],{},[74,303,304],{},"already_complete",[125,306,307],{},"Copy finished on a prior run; skip directly to CDC handoff (or finish Load).",[104,309,310,315],{},[125,311,312],{},[74,313,314],{},"reset_required",[125,316,317],{},"State exists but no longer matches the config or target reality. The run fails and asks the operator to reset.",[14,319,320],{},"The matching test is strict: if the selected table set, primary-key metadata, or source engine changed, the run fails instead of quietly re-copying into a target that may already contain rows.",[322,323],"themed-image",{"alt":324,"dark":325,"light":326},"Monitor tab showing a completed resumable load with row count, data size, Resume after Stop badge, and No data loss detected status","\u002Fimages\u002Fdocs\u002Fstreams\u002Fload-complete-dark.png","\u002Fimages\u002Fdocs\u002Fstreams\u002Fload-complete-light.png",[55,328,330],{"id":329},"reset","Reset",[14,332,333,334,336],{},"When preflight returns ",[74,335,314],{},", or when you want to rerun a failed load cleanly, clear the stored state with the reset endpoint:",[338,339,344],"pre",{"className":340,"code":341,"language":342,"meta":343,"style":343},"language-bash shiki shiki-themes github-light github-dark","curl -X POST \\\n  -H \"X-API-Key: $API_KEY\" \\\n  -H \"X-Confirm-Reset: true\" \\\n  \"$HOST\u002Fapi\u002Fv1\u002Fstream-configs\u002F$CONFIG_ID\u002Freset\"\n","bash","",[74,345,346,366,384,394],{"__ignoreMap":343},[347,348,351,355,359,363],"span",{"class":349,"line":350},"line",1,[347,352,354],{"class":353},"sScJk","curl",[347,356,358],{"class":357},"sj4cs"," -X",[347,360,362],{"class":361},"sZZnC"," POST",[347,364,365],{"class":357}," \\\n",[347,367,369,372,375,379,382],{"class":349,"line":368},2,[347,370,371],{"class":357},"  -H",[347,373,374],{"class":361}," \"X-API-Key: ",[347,376,378],{"class":377},"sVt8B","$API_KEY",[347,380,381],{"class":361},"\"",[347,383,365],{"class":357},[347,385,387,389,392],{"class":349,"line":386},3,[347,388,371],{"class":357},[347,390,391],{"class":361}," \"X-Confirm-Reset: true\"",[347,393,365],{"class":357},[347,395,397,400,403,406,409],{"class":349,"line":396},4,[347,398,399],{"class":361},"  \"",[347,401,402],{"class":377},"$HOST",[347,404,405],{"class":361},"\u002Fapi\u002Fv1\u002Fstream-configs\u002F",[347,407,408],{"class":377},"$CONFIG_ID",[347,410,411],{"class":361},"\u002Freset\"\n",[14,413,414],{},"Reset clears saved state and prepares a clean new run in one atomic sequence:",[229,416,417,423],{},[33,418,419,422],{},[36,420,421],{},"Truncates target rows"," already loaded by this stream config — so the next run starts into an empty target.",[33,424,425,428],{},[36,426,427],{},"Purges all durable recovery keys"," tied to the config: resumable load state, CDC bootstrap state, and CDC apply checkpoint.",[14,430,431,432,435],{},"The ",[74,433,434],{},"X-Confirm-Reset: true"," header is required to prevent accidental destructive resets. The stream must be stopped before reset; the API returns an error if an active run is detected.",[14,437,438,439,442],{},"For CDC streams with ",[74,440,441],{},"initialSnapshot"," on a PostgreSQL source, reset also drops the inactive replication slot.",[55,444,446],{"id":445},"monitor-visibility","Monitor visibility",[14,448,449,450,453,454,457],{},"In the ",[36,451,452],{},"Monitor"," tab, the stream header shows a load-behavior badge for ",[74,455,456],{},"mode=load"," configs:",[98,459,460,470],{},[101,461,462],{},[104,463,464,467],{},[107,465,466],{},"Badge",[107,468,469],{},"Meaning",[120,471,472,490],{},[104,473,474,479],{},[125,475,476],{},[74,477,478],{},"Resume after Stop",[125,480,481,482,485,486,489],{},"This load meets the resumable routing requirements. If the copy is interrupted with ",[36,483,484],{},"Stop",", the next ",[36,487,488],{},"Start"," continues from the next incomplete chunk.",[104,491,492,497],{},[125,493,494],{},[74,495,496],{},"Starts over after Stop",[125,498,499,500,485,502,504],{},"This load stays on the plain path. After ",[36,501,484],{},[36,503,488],{}," runs from the beginning or requires target cleanup, depending on the target policy.",[14,506,507,508,511],{},"The badge is a quick operator hint. The actual routing criteria are the ones listed in ",[21,509,58],{"href":510},"#when-the-chunked-path-is-used"," above.",[14,513,514,515,517,518,521],{},"When the badge shows ",[36,516,478],{},", a stopped run shows a ",[36,519,520],{},"Resume Load"," action in the monitor header. Click it to continue from the last saved chunk.",[322,523],{"alt":524,"dark":525,"light":526},"Monitor tab showing a stopped resumable load with saved row count, data size, and the Resume Load action","\u002Fimages\u002Fwhats-new\u002Fv2-1-load-resume-dark.png","\u002Fimages\u002Fwhats-new\u002Fv2-1-load-resume-light.png",[14,528,431,529,532,533,536],{},[74,530,531],{},"GET \u002Fstreams\u002F{id}\u002Fstats"," response includes a ",[74,534,535],{},"loadProgress"," summary while resumable copy is active:",[338,538,542],{"className":539,"code":540,"language":541,"meta":343,"style":343},"language-json shiki shiki-themes github-light github-dark","{\n  \"loadProgress\": {\n    \"status\": \"copying\",\n    \"strategy\": \"pk_range\",\n    \"mode\": \"load\",\n    \"sourceEngine\": \"mysql\",\n    \"targetEngine\": \"postgresql\",\n    \"tablesPlanned\": 2,\n    \"tablesCompleted\": 0,\n    \"chunksPlanned\": 20,\n    \"chunksCompleted\": 7,\n    \"currentTable\": \"public.orders\",\n    \"currentChunk\": 8,\n    \"updatedAt\": \"2026-04-19T09:12:03Z\",\n    \"ageSeconds\": 4\n  }\n}\n","json",[74,543,544,549,557,571,583,596,609,622,635,648,661,674,687,700,713,724,730],{"__ignoreMap":343},[347,545,546],{"class":349,"line":350},[347,547,548],{"class":377},"{\n",[347,550,551,554],{"class":349,"line":368},[347,552,553],{"class":357},"  \"loadProgress\"",[347,555,556],{"class":377},": {\n",[347,558,559,562,565,568],{"class":349,"line":386},[347,560,561],{"class":357},"    \"status\"",[347,563,564],{"class":377},": ",[347,566,567],{"class":361},"\"copying\"",[347,569,570],{"class":377},",\n",[347,572,573,576,578,581],{"class":349,"line":396},[347,574,575],{"class":357},"    \"strategy\"",[347,577,564],{"class":377},[347,579,580],{"class":361},"\"pk_range\"",[347,582,570],{"class":377},[347,584,586,589,591,594],{"class":349,"line":585},5,[347,587,588],{"class":357},"    \"mode\"",[347,590,564],{"class":377},[347,592,593],{"class":361},"\"load\"",[347,595,570],{"class":377},[347,597,599,602,604,607],{"class":349,"line":598},6,[347,600,601],{"class":357},"    \"sourceEngine\"",[347,603,564],{"class":377},[347,605,606],{"class":361},"\"mysql\"",[347,608,570],{"class":377},[347,610,612,615,617,620],{"class":349,"line":611},7,[347,613,614],{"class":357},"    \"targetEngine\"",[347,616,564],{"class":377},[347,618,619],{"class":361},"\"postgresql\"",[347,621,570],{"class":377},[347,623,625,628,630,633],{"class":349,"line":624},8,[347,626,627],{"class":357},"    \"tablesPlanned\"",[347,629,564],{"class":377},[347,631,632],{"class":357},"2",[347,634,570],{"class":377},[347,636,638,641,643,646],{"class":349,"line":637},9,[347,639,640],{"class":357},"    \"tablesCompleted\"",[347,642,564],{"class":377},[347,644,645],{"class":357},"0",[347,647,570],{"class":377},[347,649,651,654,656,659],{"class":349,"line":650},10,[347,652,653],{"class":357},"    \"chunksPlanned\"",[347,655,564],{"class":377},[347,657,658],{"class":357},"20",[347,660,570],{"class":377},[347,662,664,667,669,672],{"class":349,"line":663},11,[347,665,666],{"class":357},"    \"chunksCompleted\"",[347,668,564],{"class":377},[347,670,671],{"class":357},"7",[347,673,570],{"class":377},[347,675,677,680,682,685],{"class":349,"line":676},12,[347,678,679],{"class":357},"    \"currentTable\"",[347,681,564],{"class":377},[347,683,684],{"class":361},"\"public.orders\"",[347,686,570],{"class":377},[347,688,690,693,695,698],{"class":349,"line":689},13,[347,691,692],{"class":357},"    \"currentChunk\"",[347,694,564],{"class":377},[347,696,697],{"class":357},"8",[347,699,570],{"class":377},[347,701,703,706,708,711],{"class":349,"line":702},14,[347,704,705],{"class":357},"    \"updatedAt\"",[347,707,564],{"class":377},[347,709,710],{"class":361},"\"2026-04-19T09:12:03Z\"",[347,712,570],{"class":377},[347,714,716,719,721],{"class":349,"line":715},15,[347,717,718],{"class":357},"    \"ageSeconds\"",[347,720,564],{"class":377},[347,722,723],{"class":357},"4\n",[347,725,727],{"class":349,"line":726},16,[347,728,729],{"class":377},"  }\n",[347,731,733],{"class":349,"line":732},17,[347,734,735],{"class":377},"}\n",[98,737,738,747],{},[101,739,740],{},[104,741,742,745],{},[107,743,744],{},"Field",[107,746,469],{},[120,748,749,773,785,800,814,827,850,863],{},[104,750,751,756],{},[125,752,753],{},[74,754,755],{},"status",[125,757,758,761,762,761,765,761,768,761,771],{},[74,759,760],{},"planned",", ",[74,763,764],{},"copying",[74,766,767],{},"complete",[74,769,770],{},"failed",[74,772,314],{},[104,774,775,780],{},[125,776,777],{},[74,778,779],{},"strategy",[125,781,782,783,25],{},"Chunking strategy; currently always ",[74,784,226],{},[104,786,787,792],{},[125,788,789],{},[74,790,791],{},"mode",[125,793,794,83,797,25],{},[74,795,796],{},"load",[74,798,799],{},"cdc_bootstrap",[104,801,802,811],{},[125,803,804,807,808],{},[74,805,806],{},"chunksPlanned"," \u002F ",[74,809,810],{},"chunksCompleted",[125,812,813],{},"Aggregate chunk counts across selected tables.",[104,815,816,824],{},[125,817,818,807,821],{},[74,819,820],{},"currentTable",[74,822,823],{},"currentChunk",[125,825,826],{},"Table and chunk index currently in flight.",[104,828,829,837],{},[125,830,831,807,834],{},[74,832,833],{},"savedRows",[74,835,836],{},"savedBytes",[125,838,839,840,807,843,846,847,25],{},"Cumulative rows and bytes confirmed written across all runs for this config. ",[74,841,842],{},"runBaseRows",[74,844,845],{},"runBaseBytes"," hold the starting offset for the current run, so progress in the current run = ",[74,848,849],{},"savedRows − runBaseRows",[104,851,852,857],{},[125,853,854],{},[74,855,856],{},"lastError",[125,858,859,860,862],{},"Populated on ",[74,861,770],{},"; empty otherwise.",[104,864,865,870],{},[125,866,867],{},[74,868,869],{},"ageSeconds",[125,871,872],{},"Seconds since the last state update — useful for spotting a stalled run.",[14,874,875,876,878,879,883],{},"Row-level progress remains on the existing per-table stats; ",[74,877,535],{}," is about ",[880,881,882],"em",{},"where"," the copy is in its planned boundary.",[55,885,887],{"id":886},"stored-state","Stored state",[14,889,890,891,227],{},"State lives in the embedded NATS JetStream KV bucket ",[74,892,893],{},"streams",[30,895,896,902,908],{},[33,897,898,901],{},[74,899,900],{},"\u003CconfigID>.loadprogress"," — chunked copy cursor (version, table list, per-table min\u002Fmax\u002Fnext-lower, current chunk, last error).",[33,903,904,907],{},[74,905,906],{},"\u003CconfigID>.cdc.bootstrap"," — CDC bootstrap phase and handoff position when initial snapshot is enabled.",[33,909,910,913],{},[74,911,912],{},"\u003CconfigID>.cdc.checkpoint"," — CDC apply checkpoint after bootstrap hands off.",[14,915,916],{},"Keep the stream config to keep the state. Deleting the config removes all three keys automatically.",[55,918,920],{"id":919},"guarantees-and-boundaries","Guarantees and boundaries",[14,922,923],{},"The current release provides:",[30,925,926,929,932],{},[33,927,928],{},"crash-safe resume from the last completed chunk for eligible chunked tables",[33,930,931],{},"strict preflight instead of silent fallback when durable state and current config disagree",[33,933,934,935,937],{},"a reset endpoint for the ",[74,936,314],{}," path",[14,939,940],{},"It does not yet provide:",[30,942,943,946,949,952,955],{},[33,944,945],{},"composite primary-key chunking",[33,947,948],{},"non-numeric key strategies",[33,950,951],{},"chunked resume for PostgreSQL CDC bootstrap",[33,953,954],{},"file or S3 target resume",[33,956,957],{},"distributed chunk workers",[55,959,961],{"id":960},"related-docs","Related docs",[30,963,964,968,974,978,984],{},[33,965,966],{},[21,967,49],{"href":48},[33,969,970],{},[21,971,973],{"href":972},"\u002Fdocs\u002Fstreams\u002Fcdc-reliability-and-resume","CDC Reliability and Resume",[33,975,976],{},[21,977,24],{"href":23},[33,979,980],{},[21,981,983],{"href":982},"\u002Fdocs\u002Fstreams\u002Ftarget-data-policies","Target Data Policies",[33,985,986],{},[21,987,989],{"href":988},"\u002Fdocs\u002Fstreams\u002Fstream-config-reference","Stream Configuration Reference",[991,992,993],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":343,"searchDepth":368,"depth":368,"links":995},[996,997,998,999,1000,1001,1002,1003,1004,1005],{"id":57,"depth":368,"text":58},{"id":95,"depth":368,"text":96},{"id":201,"depth":368,"text":202},{"id":219,"depth":368,"text":220},{"id":259,"depth":368,"text":260},{"id":329,"depth":368,"text":330},{"id":445,"depth":368,"text":446},{"id":886,"depth":368,"text":887},{"id":919,"depth":368,"text":920},{"id":960,"depth":368,"text":961},"Restart a large load from the last completed chunk instead of reading the whole table again.","md",{},false,"\u002Fdocs\u002Fstreams\u002Fresumable-load",null,{"title":5,"description":1006},"docs\u002Fstreams\u002Fresumable-load","o6edSfehF7C2Z74vS3d82x-nXEaKjxwo4ev-X8-GoGk",1783896283377]