Self-hosted service
dstackai/dstack avatar
dstackai/dstack

dstack: A Vendor-Agnostic Control Plane for GPU Workloads

Vendor-agnostic orchestration for training, inference and agentic workloads across NVIDIA, AMD, TPU, and Tenstorrent on clouds, Kubernetes, and bare metal.

2,247 stars261 forksPythonMPL-2.0

At a glance

What is it?
dstack puts fleets, dev environments, tasks, services and volumes behind one CLI and one YAML schema, so the same workload definition can land on an NVIDIA cloud, a Kubernetes cluster or an on-prem SSH host. The catch is that it asks you to run a server and adopt its configuration model first.
Who is it for?
dstack fits teams that already move workloads between more than one GPU provider or between cloud and on-prem hardware, and that are willing to run a dstack server and express jobs as fleets, tasks and services in YAML. It is the wrong tool if you have a single Kubernetes cluster and a platform team already invested in raw manifests, or if you need a scheduler that owns the full lifecycle of long-running stateful workloads rather than submitting jobs to it.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, 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

The problem dstack targets: one job definition, many kinds of hardware

Most teams that train or serve models end up with a provisioning problem before they have a modelling problem. A training run needs eight GPUs of a particular class. The capacity is not there today. It is there tomorrow, on a different provider, with a different API, a different quota model and a different way of attaching storage. The script that launches the job is usually the part that rots fastest, because it encodes provider-specific assumptions that change whenever the team adds a vendor.

dstack's answer is to make the workload description portable and push the provider difference behind a server. The README describes it as a unified control plane for GPU provisioning and orchestration that works with any GPU cloud, Kubernetes, or on-prem clusters, and lists NVIDIA, AMD, Google TPU and Tenstorrent accelerators as supported out of the box. The audience is therefore not a single-cluster ML platform team. It is a team that already has, or expects to have, more than one place to run GPU work and does not want a separate submission path for each.

That framing matters because it sets the cost. You are not adopting a library you import into a training script. You are adopting a control plane, which means a server process, a client configuration, a YAML schema and a set of concepts your team has to learn.

Fleets, tasks, services and volumes: the four objects you actually write

The configuration surface is small and named. According to the README, dstack supports fleets (provision and manage clusters across clouds, Kubernetes and on-prem), dev environments (launch environments accessed by agents or from an IDE), tasks (run training, batch or other jobs across a single node or clusters), services (deploy model inference as endpoints), presets (described as agent-driven inference optimization, marked experimental) and volumes (instance and network volumes for persisting data).

Fleets are the piece that distinguishes dstack from a plain job submitter. A fleet is a provisioned pool of compute that you manage as an object, and the README notes that when using dstack with on-prem servers, backend configuration is not required: you create SSH fleets once the server is up. So there are two ways to get capacity. Either you configure a cloud or Kubernetes backend and let dstack provision, or you point it at machines you already own over SSH. Both paths end in the same fleet abstraction, which is why the same task definition can run in either place.

The YAML lives in your repository. That is stated plainly in the README, and it is a real design decision rather than a packaging detail: workload definitions are versioned alongside the code they run, and `dstack apply` reads them from there. Configuration files are not stored in the server as the source of truth.

The README also lists what dstack manages automatically once a configuration is applied: provisioning, job queuing, auto-scaling, networking, volumes, run failures, out-of-capacity errors and port-forwarding. Out-of-capacity handling is the one worth pausing on. It is the specific failure mode that makes multi-cloud GPU work painful, and treating it as an orchestration concern rather than something your launch script retries is the clearest argument for a control plane over a shell script.

Getting a server and a CLI talking to each other

The install path in the README assumes uv. To run the server you install the full extra and start it:

uv tool install "dstack[all]" -U dstack server

The server applies a configuration file at ~/.dstack/server/config.yml, prints an admin token and listens on http://127.0.0.1:3000/ by default. The README states the server runs on Linux, macOS and Windows via WSL 2, and requires Git and OpenSSH. Those two dependencies are not incidental: Git is used because configurations come from repositories, and OpenSSH because SSH fleets and port-forwarding depend on it.

The CLI is a separate install if you did not get it with the server:

uv tool install dstack -U

Then you register the server as a project, supplying the URL and the admin token printed at startup:

dstack project add \ --name main \ --url http://127.0.0.1:3000 \ --token bbae0f28-d3dd-4820-bf61-8f4bb40815da

The README notes the CLI writes its configuration to ~/.dstack/config.yml. Workloads are then submitted with `dstack apply` against a YAML file, or through a programmatic API, or through agent skills.

That last path is unusual enough to mention on its own. The README documents installing dstack skills with `npx skills add dstackai/dstack`, after which AI agents such as Claude, Codex and Cursor can create and manage fleets and submit workloads. This is a genuinely different interface to the same control plane, and it is worth treating as a real adoption consideration rather than a novelty: if your team already drives infrastructure through coding agents, dstack ships the skill definitions for that workflow.

The server is a component you now operate

The most consequential constraint is structural. Before using dstack through the CLI or API, you set up a dstack server. There is no documented mode in the README where the CLI talks directly to a cloud provider without one. That server is stateful, it holds the admin token, and it is the thing your whole team's submissions flow through.

For a small team this is manageable, and the README points to a server deployment guide for configuration options. For an organisation with strict change control, it means a new long-lived service to place, back up, upgrade and secure. The token printed at first startup is an admin token, and the README's example shows it being pasted directly into a `dstack project add` command. That is fine for a local trial. It is not a pattern to carry into a shared deployment, and the README does not present it as one; it simply does not walk through the alternatives.

The second constraint is conceptual. dstack asks you to describe work as fleets, tasks and services. If your workload does not decompose that way, you will be fighting the model. A task is described as running training, batch or other jobs across a single node or clusters. A service is described as deploying model inference as endpoints. Anything that needs a different lifecycle shape, or that expects to own its own scheduling decisions, sits awkwardly. The README does not claim otherwise, but it is the boundary a prospective adopter should test against their own workload list before committing.

The third is maturity signalling within the README itself. Presets are labelled experimental, and the news list shows a fast release cadence through 2026, including Pydantic v2 in 0.21.0, a Slurm backend in 0.20.27 and Kubernetes multiple clusters in 0.20.21. A project moving this quickly across this many backends is one where you should expect to read release notes before upgrading, not one where you can pin and forget.

Where dstack sits against Slurm and raw Kubernetes manifests

The honest comparison is not against another GPU orchestration startup. It is against the two things teams actually use today.

Slurm is a batch scheduler that owns a fixed cluster of machines. You submit jobs to it, and it decides placement within the partition you configured. dstack's model is different in kind: it provisions capacity as well as scheduling onto it, and it treats clouds, Kubernetes and SSH-accessible on-prem machines as interchangeable sources of that capacity. That is why the appearance of a Slurm backend in the 0.20.27 release is interesting. It means dstack can treat an existing Slurm cluster as one more place to put work rather than as a competing system to replace. If you already run Slurm and your problem is that you cannot burst beyond it, that backend is the relevant feature. If your problem is scheduling efficiency inside a fixed cluster, Slurm is still the tool that does that job.

Raw Kubernetes is the other comparison. If your GPU workloads already run on one Kubernetes cluster, dstack adds a layer above the manifests you already write. You gain portability to non-Kubernetes targets, out-of-capacity handling across providers, and a simpler object model for training and inference. You lose direct control over the Kubernetes objects themselves, and you take on a server plus a YAML dialect that is not Kubernetes YAML. The README's mention of Kubernetes volumes in 0.20.17 and multiple Kubernetes clusters in 0.20.21 shows the project is investing in that path, but the trade is real. A platform team that is fluent in Kubernetes and has no intention of leaving it is not obviously better off here.

Licence and the cost of keeping up

dstack is released under the Mozilla Public License 2.0. MPL-2.0 is a file-level copyleft licence: modifications to files that are part of the covered source must be made available under the same licence, while larger works that combine dstack with other code can generally be distributed under other terms. That is a different shape from a permissive licence like Apache-2.0, and different again from the strong copyleft of the GPL. Whether it matters to you depends on whether you intend to modify dstack itself and distribute the result. If you are consuming it as a service and running unmodified releases, the practical effect is limited. This is a description of the licence text, not legal advice; if you plan to fork and redistribute, have counsel read it.

The maintenance cost is the more immediate number. The release history in the supplied material shows 0.21.5 and 0.21.4 both landing on 2026-09-03, with a release candidate two days earlier, and the last push to the repository dated 2026-09-10. That is a project shipping continuously. For an operator, the relevant question is not whether it is maintained but what an upgrade from 0.21.4 to 0.21.5 requires of your server configuration and YAML. A minor version bump that touches Pydantic, as 0.21.0 did, can change validation behaviour in configuration files. The README does not describe an upgrade procedure or a compatibility policy, so that is something to establish from the release notes before you depend on it.

On the positive side, the configuration-as-YAML-in-your-repo choice means your workload definitions are diffable and reviewable, and an upgrade that changes semantics shows up as a change to files you control rather than as opaque state inside the server.

Editorial conclusion

dstack fits teams that already move workloads between more than one GPU provider or between cloud and on-prem hardware, and that are willing to run a dstack server and express jobs as fleets, tasks and services in YAML. It is the wrong tool if you have a single Kubernetes cluster and a platform team already invested in raw manifests, or if you need a scheduler that owns the full lifecycle of long-running stateful workloads rather than submitting jobs to it. Before adopting, verify three things against your own infrastructure: that the backends you actually use are listed under dstack's backend configuration docs, that the server can run somewhere your team will keep alive, and that your workloads map cleanly onto the fleet, task and service model rather than needing primitives dstack does not expose.

Official sources

  1. dstackai/dstack on GitHub
  2. License: MPL-2.0
  3. Project website
  4. README
  5. Releases
Community notes

Community notes