Open-source project
dmlc/dlpack avatar
dmlc/dlpack

DLPack: the header-only tensor bridge between deep learning frameworks

common in-memory tensor structure

1,248 stars169 forksC++Apache-2.0

At a glance

What is it?
DLPack is not a tensor library. It is a small C header that defines how one framework hands a tensor's memory to another, and the whole project lives or dies on that interface staying stable.
Who is it for?
Adopt DLPack if you are writing a framework, a runtime, or a device backend and you want your tensors to move into other people's code without a copy or a bespoke adapter. Do not adopt it if you need operators, autograd, or anything that computes; the README states plainly that the project does not intend to implement tensors and ops.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 35 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What problem DLPack actually removes

Every framework that holds a tensor in memory has its own idea of what that memory looks like: its own dtype enum, its own notion of strides, its own device identifier, its own ownership rule. When two of them need to cooperate, someone writes an adapter, and that adapter is thrown away the moment either side changes. DLPack exists to be the thing that does not get thrown away. The README frames the payoff in four ways: sharing operators between frameworks, wrapping vendor-level operator implementations so collaborators can introduce a new device or op together, swapping backend implementations such as different versions of BLAS, and, for end users, more operators and the option of mixing frameworks in one program. The audience is therefore not an application developer. It is whoever maintains the boundary between two runtimes, or whoever is tired of writing the same dtype-mapping switch for the fourth time.

The repository is a header and a staging area, nothing else

The README describes two major components. include/ holds stabilized headers. contrib/ holds in-progress unstable libraries. That split is the entire architecture, and it tells you how to treat the project. If you vendor something from include/, you are consuming a frozen contract. If you pull from contrib/, you are consuming a moving target and should expect it to change without the ceremony that a stabilized header would get. There is no runtime, no build artifact you link against in the usual sense, and no service. A project that ships a header has an unusual failure mode: it cannot break at runtime on its own, it breaks when two implementations disagree about what the header means. That is why the stabilization boundary matters more here than in a library with a versioned binary. The README also names the people involved in the RFC design proposals, including @soumith, @piiswrong, @Yangqing, @naibaf7, @bhack, @edgarriba, @tqchen, @prigoyal and @zdevito. That list is the clearest evidence in the material that this is a cross-vendor agreement rather than one team's internal format.

How a change gets into the header

The governance is stated in two sentences and it is worth reading literally. RFC proposals are opened as issues. The major release happens as a vote issue, so that participants agree on the changes. This is slower than a normal open source merge and it is intentional. A tensor interchange format is a coordination artifact: if one framework ships a variant of the struct, every consumer has to handle both. The vote requirement means a major release is a negotiated event rather than a maintainer's judgement call. The practical consequence for an adopter is that you should expect long gaps between major versions and should not expect a quick fix for an edge case you hit. The recent release history is consistent with that: v1.1 in March 2025, v1.2 in October 2025, v1.3 in January 2026. Three releases across roughly a year, each one a decision point for every framework that consumes the header.

Getting it into a build

Because the deliverable is a header, integration is a checkout rather than a package install. The README points to the documentation at https://dmlc.github.io/dlpack/latest and the repository is laid out so that include/ can be added to a compiler's include path directly. The README does not give a copy-pasteable build command, a CMake target name, or a package manager invocation, so treat any specific command you see elsewhere as unverified against this material. What the README does establish is the versioning surface: releases are tagged v1.1, v1.2, v1.3, and the default branch is main. If you vendor the header, pin to a tag rather than to main, since main is where pre-vote changes will land. The contrib/ directory is the other half of the integration story and it carries a different expectation: the README calls it in progress and unstable, so code that depends on it should be prepared to track changes between releases rather than assume the stabilised-header guarantee applies.

Where a spec-only project stops being enough

The most important sentence in the README is the one about scope: the project does not intend to implement Tensor and Ops, and instead uses the format as a common bridge to reuse tensors and ops across frameworks. Read that as a hard boundary, not modesty. DLPack will not validate that the strides you set are legal for the shape you declared. It will not tell you who owns the buffer after the handoff, beyond whatever the structure's fields express. It will not catch a dtype enum that one side mapped to the wrong width. Those are the bugs you will actually hit, and they surface as wrong numbers or corrupted memory in the consuming framework, far from the line of code that produced the tensor. If your team wants a library that owns tensor semantics end to end, this is the wrong tool and the README says so. If you want a format that two independent runtimes can agree on without either one owning the other, this is what it is for.

The alternative is writing your own adapter, and here is the real difference

The obvious alternative is a direct adapter between two specific frameworks: a function in framework A that reads A's tensor type and constructs B's tensor type. That approach is faster to write for a single pair and it can encode semantics the shared format deliberately leaves out, such as whether a lazy or deferred buffer should be materialised at the boundary. The difference in approach is the shape of the maintenance burden. A pairwise adapter is O(n squared) in the number of frameworks: every new runtime needs a converter to and from each existing one, and each converter is owned by whoever wrote it. A shared struct is O(n): each runtime implements the format once and reaches every other participant. The cost of the shared approach is that the format can only express what all participants agree on, which is why the RFC and vote process exists and why it is slow. If you only ever need two frameworks to talk, the adapter is cheaper and you should write it. The shared format pays off at the third participant.

Licence and the cost of staying current

DLPack is Apache-2.0, which is a permissive licence with an explicit patent grant, and that matters for a format that device vendors are expected to implement. Vendoring the header into a proprietary runtime is the kind of use the licence is designed to permit, but the terms are the terms and you should read them rather than take a summary from an article. On maintenance: the upgrade cost is not a dependency bump. Because a major release is a vote issue, moving from one major version to the next is a coordination decision that may require changes in every framework you exchange tensors with, not just in your own code. A runtime that speaks v1.2 and a runtime that speaks v1.3 have to agree on which side adapts. The cheap path is to implement against a pinned tag and to read the RFC issues before the next vote, so you know what is coming while it is still a proposal rather than after it ships.

Editorial conclusion

Adopt DLPack if you are writing a framework, a runtime, or a device backend and you want your tensors to move into other people's code without a copy or a bespoke adapter. Do not adopt it if you need operators, autograd, or anything that computes; the README states plainly that the project does not intend to implement tensors and ops. Before you depend on it, check the include/ headers against the version tag you plan to pin, and read the open RFC issues to see which parts of the structure are still in motion.

Official sources

  1. dmlc/dlpack on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Community notes

Community notes