The protocol assumes establishing a duplex asynchronous communication channel between the parties.A separate session of message exchanges is open for a single pull or push operation,
and it is closed automatically after the intended operation is complete or fails with an error.For a pull operation:
Client initiates the request to the Server, sending the ID of the dataset and a desired block range
Server responds by sending a tarball of metadata that matches the requested block range
Client analyzes the received blocks and identifiers missing object files (such as data slices, checkpoints)
Client negotiates with the Server on the download method for a subset or full set of missing object files:
for each object file, Server creates a time-limited pre-signed download URL with read-only access the storage system
Client directly reads the objects files from the storage system via pre-signed URLs
the negotiation can repeat for another subset of missing object files
Client commits the new synchronized blocks, and closes the operation
For a push operation:
Client initiates the request to the Server, sending the ID of the dataset and a tarball of the new metadata blocks
If Server does not detect a divergence in the metadata, it confirms the Client may proceed synchronizing objects
Client negotiates with the Server on the upload method for a subset or full set of new object files:
for each object file, Server creates a time-limited pre-signed upload URL with write-only access to the storage system
Client directly uploads the object files to the storage system via pre-signed URLs
the negotiation can repeat for another subset of new object files
Client informs the Server about completion of the objects synchronization
Server verifies the required objects exist and attempts to commit the new metadata blocks
In case of success, the Server confirms the commit succeeded, and closes the operation
The exchange of object files should be performed with delays and object sizes taken into account.
As the expiration time of pre-signed URLs is limited, in case of large bulks have to be exchanged,
the pre-signed URLs might expire before the actual transfer starts - in this case they need to be re-requested.The parallelism of the object download/upload operations to/from storage system is not limited by the protocol,
neither is to be constrained by the server. It’s considered to be an implementation detail of the Client.In case of errors, timeouts, the Client needs to re-initiate the operation with the Server by opening another session.
New operation may skip the synchronization of the already processed object files from the previous sessions,
even if the changes have not been finally committed to the metadata. Cleaning orphan files that accumulate on transfer errors
is a subject for a separate Garbage Collector mechanism within the dataset storage, that is out of the scope of this RFC.The protocol can be implemented using WebSockets or any other
alternative type of channel that supports bi-directional non-blocking message exchanges.
OpenAPI is a superset of REST API endpoints as defined in the
Simple Transfer Protocol, with extensions to establish
asynchronous duplex messaging channel as defined by AsyncAPI.
DeltaSharing can be implemented as a separate protocol reusing a lot of the parts from this
A detection of unfinished pushes can be added to clean up orphaned files without doing a full GC run on a dataset
Last modified on October 15, 2026
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Kamu Docs","colors":{"primary":"#ec6e2a","light":"#ec6e2a","dark":"#ec6e2a"},"logo":{"light":"https://mintcdn.com/kamu/j1tx5fgzyFHd1DYS/images/kamu-logo-light.svg?fit=max\u0026auto=format\u0026n=j1tx5fgzyFHd1DYS\u0026q=85\u0026s=a09261b617da6e1515dea3d28495f633","dark":"https://mintcdn.com/kamu/j1tx5fgzyFHd1DYS/images/kamu-logo-dark.svg?fit=max\u0026auto=format\u0026n=j1tx5fgzyFHd1DYS\u0026q=85\u0026s=8c6d0d7ffa23ef050859453f64354192"},"favicon":"https://mintcdn.com/kamu/j1tx5fgzyFHd1DYS/images/favicon.svg?fit=max\u0026auto=format\u0026n=j1tx5fgzyFHd1DYS\u0026q=85\u0026s=a7b01f8f352427f5a4afe3aef1f8a9d3","background":{"color":{"dark":"#050C1E"}},"navbar":{"links":[{"href":"https://discord.gg/nU6TXRQNXC","label":"Get Help"}],"primary":{"type":"button","label":"Install","href":"/cli/install/"}},"footer":{"socials":{"github":"https://github.com/kamu-data","discord":"https://discord.gg/nU6TXRQNXC","youtube":"https://www.youtube.com/@kamudata","linkedin":"https://www.linkedin.com/company/kamu-data","medium":"https://medium.com/kamu-data","bluesky":"https://bsky.app/profile/kamu.dev","x":"https://x.com/kamu_data"},"links":[{"header":"Company","items":[{"label":"Blog","href":"https://kamu.dev/blog"},{"label":"Careers","href":"https://kamu.dev/jobs"}]}]},"seo":{"metatags":{"canonical":"https://docs.kamu.dev"}},"styling":{"eyebrows":"breadcrumbs","latex":false},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","mcp","cursor","vscode"],"display":"header"},"metadata":{"timestamp":true},"navigation":{"global":{"anchors":[]},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"kamu","hasAudioNarration":false,"actualSubdomain":"kamu","customDomains":["docs.kamu.dev"],"gitSource":{"type":"github","owner":"kamu-data","repo":"kamu-docs","deployBranch":"master","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6ad05633011b02bffcb4463d","collectionId":"0127742b-6059-4668-b046-f443923b1bdd","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ad05633011b02bffcb4463d"},"entitlements":{},"buildId":"6ad05633011b02bffcb4463d","clientVersion":"0.0.3964","searchFilterCounts":[{"language":"default","tag":"Guides","count":75},{"language":"default","tag":"Reference","count":42},{"language":"default","tag":"Open Data Fabric","count":39},{"language":"default","tag":"Kamu CLI","count":31},{"language":"default","tag":"RFCs","count":22},{"language":"default","tag":"Kamu Node","count":17},{"language":"default","tag":"Specification","count":15},{"language":"default","tag":"APIs","count":13},{"language":"default","tag":"Get Started","count":12},{"language":"default","tag":"Datasets","count":10}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-v7-file-tree","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"pause-universal-search-reconcile","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"per-site-search-delta","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-private-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-nav-generations","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-agent-model-picker","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"isAtlas":false,"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":"a.card:is(.dark *),div.card:is(.dark *){background:#09162d}a.card:is(.light *),div.card:is(.light *){background:#fafafa}a:has(svg[style*=\"wrench.svg\"]){pointer-events:none;opacity:.7}button:has(svg[style*=\"wrench.svg\"]){opacity:.7}a:has(svg[style*=\"wrench.svg\"])>div:first-child,button:has(svg[style*=\"wrench.svg\"])>svg[style*=\"wrench.svg\"]{order:2;margin-left:auto}.prose a.glossary-term:is(.dark *, .light *){color:inherit;font-weight:inherit;border-bottom:2px dotted #325495}.prose a.schema-object:is(.dark *, .light *){color:inherit;font-weight:inherit;border-bottom:2px dotted #2c802c}h4.project-title:is(.dark *, .light *){display:block;text-align:center}div.badges a,h4.project-title a{border-bottom:0}a.project-quicklink:is(.dark *, .light *){font-size:15px;font-weight:300;color:#ec6e2a;border-bottom:0}.prose div img:is(\n [src*=\"projects/odf.svg\"],\n [src*=\"projects/kamu-cli.svg\"],\n [src*=\"projects/kamu-node.svg\"],\n [src*=\"projects/kamu-platform.svg\"]\n ){display:block;margin:30px auto 0;height:100px;width:auto}div.badges{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;gap:10px;margin:20px}div.badges img{display:inline;margin:0}"}],"page":{"pagePath":"odf/rfcs/008-smart-transfer-protocol","slug":"/odf/rfcs/008-smart-transfer-protocol","pageMetadata":{"title":"RFC-008: Smart Transfer Protocol","description":null,"href":"/odf/rfcs/008-smart-transfer-protocol"},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];const YouTubeList=({id})=>{const src=`https://www.youtube.com/embed/videoseries?list=${id}`;return _jsx(`iframe`,{className:`mint-w-full mint-aspect-video mint-rounded-xl`,src,allow:`accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture`,allowFullScreen:true})};const YouTube=({id,width})=>{const src=`https://www.youtube.com/embed/${id}`;return _jsx(`iframe`,{className:`mint-w-full mint-aspect-video mint-rounded-xl`,src,allow:`accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture`,allowFullScreen:true,width})};const Schema=({t,id})=>{const _components={a:`a`,..._provideComponents()};const anchor=id?id:t.toLowerCase().replace(/\\s+/g,`-`);const link=`/odf/schemas#${anchor}`;return _jsx(_components.a,{class:`schema-object`,href:link,children:t})};const Term=({t,id})=>{const _components={a:`a`,..._provideComponents()};const anchor=id?id:t.toLowerCase().replace(/\\s+/g,`-`);const link=`/general/glossary#${anchor}`;return _jsx(_components.a,{class:`glossary-term`,href:link,children:t})};const Diagram=({src,alt})=>{return _jsxs(`div`,{style:{display:`flex`,\"flex-direction\":`column`,\"align-items\":`center`},children:[_jsx(`img`,{src,alt,style:{background:`#dddddd`,\"margin-bottom\":0}}),_jsx(`span`,{children:alt})]})};function _createMdxContent(props){const _components={a:`a`,code:`code`,img:`img`,li:`li`,p:`p`,strong:`strong`,ul:`ul`,..._provideComponents(),...props.components},{Heading,_MdxComponentBoundary}=_components;if(!Heading)_missingMdxReference(`Heading`,true);if(!_MdxComponentBoundary)_missingMdxReference(`_MdxComponentBoundary`,true);return _jsxs(_Fragment,{children:[_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Start Date`}),`: 2022-12-23`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Specs`}),`:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:_jsx(_components.a,{href:`/odf/spec/exchange/transfer-protocols`,children:`Transfer Protocols`})}),`\n`]}),`\n`,_jsx(_components.p,{children:_jsx(_components.a,{href:`https://github.com/kamu-data/open-data-fabric/issues/35`,children:_jsx(_components.img,{src:`https://img.shields.io/github/issues/detail/state/kamu-data/open-data-fabric/35?label=RFC%20Status`,alt:`RFC Status`})})}),`\n`,_jsx(_components.p,{children:_jsx(_components.a,{href:`https://github.com/kamu-data/open-data-fabric/pull/38`,children:_jsx(_components.img,{src:`https://img.shields.io/github/pulls/detail/state/kamu-data/open-data-fabric/38?label=Spec%20PR`,alt:`Spec PR`})})}),`\n`,_jsx(Heading,{level:`2`,id:`summary`,children:`Summary`}),`\n`,_jsx(_components.p,{children:`An enhanced read/write transfer protocol that can be used to efficiently synchronize remote dataset repositories.`}),`\n`,_jsx(Heading,{level:`2`,id:`motivation`,children:`Motivation`}),`\n`,_jsxs(_components.p,{children:[`The performance limitations of the `,_jsx(_components.a,{href:`/odf/rfcs/007-simple-transfer-protocol`,children:`Simple Transfer Protocol`}),` are significant:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`the exchange becomes noticeably slow on datasets with >200 files, there is no use of batching, compression`}),`\n`,_jsx(_components.li,{children:`proxied push/pull are not allowed (being able to read/write directly from/to S3 instead of overloading the servers)`}),`\n`]}),`\n`,_jsx(_components.p,{children:`Another limitation this protocol is trying to address is that HTTP-based dataset sharing should not be read-only.`}),`\n`,_jsx(Heading,{level:`2`,id:`guide-level-explanation`,children:`Guide-level explanation`}),`\n`,_jsx(_components.p,{children:`The protocol assumes establishing a duplex asynchronous communication channel between the parties.`}),`\n`,_jsx(_components.p,{children:`A separate session of message exchanges is open for a single pull or push operation,\nand it is closed automatically after the intended operation is complete or fails with an error.`}),`\n`,_jsxs(_components.p,{children:[`For a `,_jsx(_components.code,{children:`pull`}),` operation:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Client initiates the request to the Server, sending the ID of the dataset and a desired block range`}),`\n`,_jsx(_components.li,{children:`Server responds by sending a tarball of metadata that matches the requested block range`}),`\n`,_jsx(_components.li,{children:`Client analyzes the received blocks and identifiers missing object files (such as data slices, checkpoints)`}),`\n`,_jsxs(_components.li,{children:[`Client negotiates with the Server on the download method for a subset or full set of missing object files:`,`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`for each object file, Server creates a time-limited pre-signed download URL with read-only access the storage system`}),`\n`,_jsx(_components.li,{children:`Client directly reads the objects files from the storage system via pre-signed URLs`}),`\n`,_jsx(_components.li,{children:`the negotiation can repeat for another subset of missing object files`}),`\n`]}),`\n`]}),`\n`,_jsx(_components.li,{children:`Client commits the new synchronized blocks, and closes the operation`}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`For a `,_jsx(_components.code,{children:`push`}),` operation:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Client initiates the request to the Server, sending the ID of the dataset and a tarball of the new metadata blocks`}),`\n`,_jsx(_components.li,{children:`If Server does not detect a divergence in the metadata, it confirms the Client may proceed synchronizing objects`}),`\n`,_jsxs(_components.li,{children:[`Client negotiates with the Server on the upload method for a subset or full set of new object files:`,`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`for each object file, Server creates a time-limited pre-signed upload URL with write-only access to the storage system`}),`\n`,_jsx(_components.li,{children:`Client directly uploads the object files to the storage system via pre-signed URLs`}),`\n`,_jsx(_components.li,{children:`the negotiation can repeat for another subset of new object files`}),`\n`]}),`\n`]}),`\n`,_jsx(_components.li,{children:`Client informs the Server about completion of the objects synchronization`}),`\n`,_jsx(_components.li,{children:`Server verifies the required objects exist and attempts to commit the new metadata blocks`}),`\n`,_jsx(_components.li,{children:`In case of success, the Server confirms the commit succeeded, and closes the operation`}),`\n`]}),`\n`,_jsx(_components.p,{children:`The exchange of object files should be performed with delays and object sizes taken into account.\nAs the expiration time of pre-signed URLs is limited, in case of large bulks have to be exchanged,\nthe pre-signed URLs might expire before the actual transfer starts - in this case they need to be re-requested.`}),`\n`,_jsx(_components.p,{children:`The parallelism of the object download/upload operations to/from storage system is not limited by the protocol,\nneither is to be constrained by the server. It’s considered to be an implementation detail of the Client.`}),`\n`,_jsx(_components.p,{children:`In case of errors, timeouts, the Client needs to re-initiate the operation with the Server by opening another session.\nNew operation may skip the synchronization of the already processed object files from the previous sessions,\neven if the changes have not been finally committed to the metadata. Cleaning orphan files that accumulate on transfer errors\nis a subject for a separate Garbage Collector mechanism within the dataset storage, that is out of the scope of this RFC.`}),`\n`,_jsxs(_components.p,{children:[`The protocol can be implemented using `,_jsx(_components.a,{href:`https://websockets.spec.whatwg.org//`,children:`WebSockets`}),` or any other\nalternative type of channel that supports bi-directional non-blocking message exchanges.`]}),`\n`,_jsx(Heading,{level:`2`,id:`reference-level-explanation`,children:`Reference-level explanation`}),`\n`,_jsx(_components.p,{children:`Smart Transfer Protocol defines 2 kinds of APIs:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`OpenAPI`}),` `,_jsx(_components.a,{href:`https://github.com/open-data-fabric/open-data-fabric/blob/master/contracts/transfer/smart-transfer-protocol.openapi.yaml`,children:`description of the initial REST endpoints`}),`.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`AsyncAPI`}),` `,_jsx(_components.a,{href:`https://github.com/open-data-fabric/open-data-fabric/blob/master/contracts/transfer/smart-transfer-protocol.asyncapi.yaml`,children:`description of the protocol messages`}),`.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`OpenAPI`}),` is a superset of REST API endpoints as defined in the\n`,_jsx(_components.a,{href:`/odf/rfcs/007-simple-transfer-protocol`,children:`Simple Transfer Protocol`}),`, with extensions to establish\nasynchronous duplex messaging channel as defined by `,_jsx(_components.code,{children:`AsyncAPI`}),`.`]}),`\n`,_jsx(Heading,{level:`3`,id:`push-flow`,children:`Push flow`}),`\n`,_jsx(_MdxComponentBoundary,{name:`Diagram`,children:_jsx(Diagram,{src:`/images/odf/specs/exchange/transfer-protocols/smart_transfer_protocol_push.svg`,alt:`Diagram: ODF Smart TransferProtocol Push`})}),`\n`,_jsx(Heading,{level:`3`,id:`pull-flow`,children:`Pull flow`}),`\n`,_jsx(_MdxComponentBoundary,{name:`Diagram`,children:_jsx(Diagram,{src:`/images/odf/specs/exchange/transfer-protocols/smart_transfer_protocol_pull.svg`,alt:`Diagram: ODF Smart TransferProtocol Pull`})}),`\n`,_jsx(Heading,{level:`2`,id:`drawbacks`,children:`Drawbacks`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Ended up with a custom protocol rather than reusing some standard`}),`\n`,_jsx(_components.li,{children:`Asynchronous duplex messaging APIs are harder to test`}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`alternatives`,children:`Alternatives`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`Considered implementing the protocol in the form of synchronous request-response REST API:`,`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`Good parts:`,`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Better portability (although, not really relevant in 2023 by now)`}),`\n`,_jsx(_components.li,{children:`Easier to test the implementations`}),`\n`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`Bad parts:`,`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Requires modeling push flows as a long-running operation with the state stored in the DB`}),`\n`,_jsx(_components.li,{children:`More complex state recovery logic in case of resume/cancellation`}),`\n`,_jsx(_components.li,{children:`Potential re-iteration over the same metadata chain, as messages get split between independent stateless calls`}),`\n`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`Decision:`,`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Refused in favor of asynchronous bi-directional messaging API`}),`\n`]}),`\n`]}),`\n`]}),`\n`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`prior-art`,children:`Prior art`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:_jsx(_components.a,{href:`https://git-scm.com/book/en/v2/Git-Internals-Transfer-Protocols`,children:`Git’s “Smart Protocol”`})}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`https://github.com/delta-io/delta-sharing/blob/main/PROTOCOL.md`,children:`DeltaSharing`}),`:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`Good parts:`,`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Simple - can easily support this protocol if needed`}),`\n`,_jsxs(_components.li,{children:[`Choice of [application/x-ndjson] (`,_jsx(_components.a,{href:`https://github.com/ndjson/ndjson-spec`,children:`https://github.com/ndjson/ndjson-spec`}),`) encoding`]}),`\n`,_jsx(_components.li,{children:`human-readable`}),`\n`,_jsx(_components.li,{children:`easy to parse`}),`\n`,_jsx(_components.li,{children:`self-delimiting`}),`\n`,_jsx(_components.li,{children:`efficient for streaming / iterative production and consumption`}),`\n`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`Bad parts:`,`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Very “egocentric” - designed mostly just with Databricks’ own case in mind`}),`\n`,_jsx(_components.li,{children:`Uses Spark-specific schema format - not even Parquet, which would be a much better lower-level abstraction`}),`\n`,_jsx(_components.li,{children:`Using “SQL subset” for predicate hints (pre-filters)`}),`\n`,_jsx(_components.li,{children:`Change Data Feed API is Delta Lake specific`}),`\n`,_jsx(_components.li,{children:`Leaks the format of CDF files that show INSERT/UPDATE/DELETE/MERGE operations`}),`\n`,_jsx(_components.li,{children:`Forces share/schema/table hierarchy upon server which is unnecessary`}),`\n`]}),`\n`]}),`\n`]}),`\n`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`unresolved-questions`,children:`Unresolved questions`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`Garbage Collector mechanism within the dataset storage, as orphaned files may occur:`,`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`when client failed to upload the objects and did not commit the push`}),`\n`,_jsx(_components.li,{children:`when late collision happens (parallel pushes)`}),`\n`]}),`\n`]}),`\n`,_jsx(_components.li,{children:`Should this protocol support live-streaming of datasets?`}),`\n`,_jsxs(_components.li,{children:[`Should it support in-band data transfers?`,`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`And if yes, should it be used for query results or for getting data from projections?`}),`\n`]}),`\n`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`future-possibilities`,children:`Future possibilities`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`DeltaSharing can be implemented as a separate protocol reusing a lot of the parts from this`}),`\n`,_jsx(_components.li,{children:`A detection of unfinished pushes can be added to clean up orphaned files without doing a full GC run on a dataset`}),`\n`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{YouTubeList,YouTube,Schema,Term,Diagram,default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"RFC-008: Smart Transfer Protocol","description":null,"href":"/odf/rfcs/008-smart-transfer-protocol"}}},"mdxSourceWithNoJs":null,"noJsSplices":[[147,1427,")=>null;const YouTube=()=>null;const Schema=()=>null;const Term=()=>null;const Diagram=()=>null;func"]]},"mdxExtracts":{"tableOfContents":[{"title":"Summary","slug":"summary","depth":2,"children":[]},{"title":"Motivation","slug":"motivation","depth":2,"children":[]},{"title":"Guide-level explanation","slug":"guide-level-explanation","depth":2,"children":[]},{"title":"Reference-level explanation","slug":"reference-level-explanation","depth":2,"children":[{"title":"Push flow","slug":"push-flow","depth":3,"children":[]},{"title":"Pull flow","slug":"pull-flow","depth":3,"children":[]}]},{"title":"Drawbacks","slug":"drawbacks","depth":2,"children":[]},{"title":"Alternatives","slug":"alternatives","depth":2,"children":[]},{"title":"Prior art","slug":"prior-art","depth":2,"children":[]},{"title":"Unresolved questions","slug":"unresolved-questions","depth":2,"children":[]},{"title":"Future possibilities","slug":"future-possibilities","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"dynamicCss":".mint-aspect-video {\n aspect-ratio: 16 / 9\n}\n.mint-w-full {\n width: 100%\n}\n.mint-rounded-xl {\n border-radius: 0.75rem\n}","subdomain":"kamu","siteName":"Kamu Docs","title":"RFC-008: Smart Transfer Protocol - Kamu Docs","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-15T04:13:42.410Z","gitLastModified":"2026-10-15T04:13:20.000Z","originalFileLocation":"odf/rfcs/008-smart-transfer-protocol.md"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"application-name\" content=\"Kamu Docs\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"RFC-008: Smart Transfer Protocol - Kamu Docs\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Kamu Docs\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.kamu.dev/odf/rfcs/008-smart-transfer-protocol\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://kamu.mintlify.app/_mintlify/api/og/v2?division=RFCs\u0026amp;title=RFC-008%3A+Smart+Transfer+Protocol\u0026amp;theme=4425de33767c8dc7c1d6072e\u0026amp;signature=ffb45ce9cb8576199c57a5783597091fcc99ad5a172d236d8fda069040242638\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"RFC-008: Smart Transfer Protocol - Kamu Docs\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://kamu.mintlify.app/_mintlify/api/og/v2?division=RFCs\u0026amp;title=RFC-008%3A+Smart+Transfer+Protocol\u0026amp;theme=4425de33767c8dc7c1d6072e\u0026amp;signature=ffb45ce9cb8576199c57a5783597091fcc99ad5a172d236d8fda069040242638\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Kamu Docs\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#ec6e2a\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.kamu.dev/odf/rfcs/008-smart-transfer-protocol\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/odf/rfcs/008-smart-transfer-protocol.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.kamu.dev/#organization\",\"name\":\"Kamu Docs\",\"url\":\"https://docs.kamu.dev\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/kamu/j1tx5fgzyFHd1DYS/images/kamu-logo-light.svg?fit=max\u0026auto=format\u0026n=j1tx5fgzyFHd1DYS\u0026q=85\u0026s=a09261b617da6e1515dea3d28495f633\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.kamu.dev#website\",\"name\":\"Kamu Docs\",\"url\":\"https://docs.kamu.dev\",\"publisher\":{\"@id\":\"https://docs.kamu.dev/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.kamu.dev/odf/rfcs/008-smart-transfer-protocol#webpage\",\"url\":\"https://docs.kamu.dev/odf/rfcs/008-smart-transfer-protocol\",\"name\":\"RFC-008: Smart Transfer Protocol\",\"dateModified\":\"2026-10-15T04:13:20.000Z\",\"isPartOf\":{\"@id\":\"https://docs.kamu.dev#website\"},\"breadcrumb\":{\"@id\":\"https://docs.kamu.dev/odf/rfcs/008-smart-transfer-protocol#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.kamu.dev/odf/rfcs/008-smart-transfer-protocol#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Open Data Fabric\",\"item\":\"https://docs.kamu.dev/odf/about\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"RFCs\",\"item\":\"https://docs.kamu.dev/odf/rfcs/index\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"RFC-008: Smart Transfer Protocol\",\"item\":\"https://docs.kamu.dev/odf/rfcs/008-smart-transfer-protocol\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.kamu.dev/odf/rfcs/008-smart-transfer-protocol#article\",\"headline\":\"RFC-008: Smart Transfer Protocol\",\"name\":\"RFC-008: Smart Transfer Protocol\",\"url\":\"https://docs.kamu.dev/odf/rfcs/008-smart-transfer-protocol\",\"mainEntityOfPage\":{\"@id\":\"https://docs.kamu.dev/odf/rfcs/008-smart-transfer-protocol#webpage\"},\"dateModified\":\"2026-10-15T04:13:20.000Z\",\"publisher\":{\"@id\":\"https://docs.kamu.dev/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.kamu.dev#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Kamu Docs\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Kamu Docs","nav":{"global":{"anchors":[]},"tabs":[{"tab":"Guides","icon":"person-chalkboard","pages":[{"title":"Guides","href":"/start/welcome"}]},{"tab":"Reference","icon":"book-open-cover","groups":[{"group":"Open Data Fabric","pages":[{"title":null,"href":"/odf/about"},{"group":"Specification","root":{"title":"Overview","href":"/odf/spec/overview"},"pages":[{"group":"Datasets","pages":[{"title":"Logical Structure","href":"/odf/spec/datasets/logical-structure"},{"title":"Identity","href":"/odf/spec/datasets/identity"},{"title":"Data Model","href":"/odf/spec/datasets/data-model"},{"title":"Data Schema","href":"/odf/spec/datasets/data-schema"},{"title":"Metadata Chain","href":"/odf/spec/datasets/metadata-chain"},{"title":"Data \u0026 Checkpoint Hashing","href":"/odf/spec/datasets/data-and-checkpoint-hashing"},{"title":"Storage Layout","href":"/odf/spec/datasets/storage-layout"},{"title":"Ingestion","href":"/odf/spec/datasets/ingestion"}]},{"group":"Transformations","pages":[{"title":"Processing Model","href":"/odf/spec/transformations/processing-model"},{"title":"Engine Contract","href":"/odf/spec/transformations/engine-contract"}]},{"group":"Exchange","pages":[{"title":"Transfer Protocols","href":"/odf/spec/exchange/transfer-protocols"},{"title":"Verifiable Batch Queries","href":"/odf/spec/exchange/verifiable-batch-queries"}]},{"group":"Automation","pages":[{"title":"Resource Framework","href":"/odf/spec/automation/resource-framework"},{"title":"Tasks and Flows","href":"/odf/spec/automation/tasks-and-flows"}]},{"group":"Auth \u0026 Privacy","pages":[{"title":"Authorization","href":"/odf/spec/auth-and-privacy/authorization"}]}]},{"title":"Schemas","href":"/odf/schemas"},{"group":"RFCs","root":{"title":"RFCs","href":"/odf/rfcs/index"},"pages":[{"title":"RFC-001: Record Offsets","href":"/odf/rfcs/001-record-offsets"},{"title":"RFC-002: Logical Data Digests","href":"/odf/rfcs/002-logical-data-hashes"},{"title":"RFC-003: Content Addressability","href":"/odf/rfcs/003-content-addressability"},{"title":"RFC-004: Metadata Extensibility","href":"/odf/rfcs/004-metadata-extensibility"},{"title":"RFC-005: New Annotation Metadata Events","href":"/odf/rfcs/005-dataset-annotations"},{"title":"RFC-006: Store Checkpoints as Files","href":"/odf/rfcs/006-checkpoints-as-files"},{"title":"RFC-007: Simple Transfer Protocol","description":null,"href":"/odf/rfcs/007-simple-transfer-protocol"},{"title":"RFC-008: Smart Transfer Protocol","href":"/odf/rfcs/008-smart-transfer-protocol"},{"title":"RFC-009: Ingestion Source State","description":null,"href":"/odf/rfcs/009-ingest-source-state"},{"title":"RFC-010: Data Schema in Metadata","href":"/odf/rfcs/010-data-schema-in-metadata"},{"title":"RFC-011: Push Ingest Sources","href":"/odf/rfcs/011-push-ingest-sources"},{"title":"RFC-012: Recommend `base16` encoding for textual representation of hashes and DIDs","href":"/odf/rfcs/012-recommend-base16-encoding"},{"title":"RFC-013: Enum representation in YAML encoding","href":"/odf/rfcs/013-yaml-enum-representation"},{"title":"RFC-014: Minimizing scanning for last offset and block","href":"/odf/rfcs/014-minimize-offset-scanning"},{"title":"RFC-015: Unified changelog stream schema","href":"/odf/rfcs/015-unified-changelog-stream-schema"},{"title":"RFC-016: ODF Schema Format","href":"/odf/rfcs/016-odf-schema"},{"title":"RFC-017: Large Files Linking","href":"/odf/rfcs/017-large-files-linking"},{"title":"RFC-018: Infrastructure-as-Code Resource Framework","href":"/odf/rfcs/018-iac-resource-framework"},{"title":"RFC-019: IaC Task and Flow System","href":"/odf/rfcs/019-iac-task-flow-system"},{"title":"RFC-020: Authorization Model","href":"/odf/rfcs/020-auth"},{"title":"RFC-021: ODF Spec Restructuring","href":"/odf/rfcs/021-spec-restructuring"},{"title":"RFC-022: Batch Query Commitments","href":"/odf/rfcs/022-batch-query-commitments"}]}]},{"group":"Kamu CLI","pages":[{"title":"Commands Reference","href":"/cli/commands"},{"title":"Config Reference","href":"/cli/config"}]},{"group":"Kamu Node","pages":[{"title":"Config Reference","href":"/node/config"}]}]},{"tab":"APIs","icon":"code","pages":[{"title":"APIs","href":"/api/overview"}]},{"tab":"Integrations","icon":"network-wired","pages":[{"title":"Integrations","href":"/integrations/overview"}]}]},"title":"RFC-008: Smart Transfer Protocol - Kamu Docs","buildId":"dpl_HcHmUS6i3UwswnTHJUEdcTtwfdTQ","deploymentId":"dpl_HcHmUS6i3UwswnTHJUEdcTtwfdTQ","dynamics":["a74be98ba7"],"chunks":["zoom-image-lightbox-CFBqa0On.js","lightbox-handle-r17bVUz3.js"]}