Model or dataset
basetenlabs/truss avatar
basetenlabs/truss

Truss: a Python CLI that turns a config.yaml into a Baseten endpoint

The simplest way to serve AI/ML models in production

1,203 stars126 forksPythonMIT

At a glance

What is it?
Truss is the CLI for packaging and deploying models on Baseten, and the README's quickstart shows a deployment that needs no Python and no Dockerfile. The catch is that the interesting half of the workflow runs on Baseten's infrastructure, not on your machine.
Who is it for?
Adopt Truss if your serving target is Baseten and you want a config.yaml plus `uvx truss push` instead of a Dockerfile and a Kubernetes manifest. Do not adopt it if you need a vendor-neutral artifact you can run on your own scheduler, since the documented path assumes Baseten accounts, Baseten API keys, and Baseten-side compilation.
Can I use it commercially?
Yes. MIT 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 1 day ago.
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 Truss addresses is the gap between a model directory and a reachable endpoint

A trained checkpoint on disk is not a service. Between the two sit a container image, pinned dependencies, a serving process, a GPU allocation, and a URL that something else can call. Truss exists to collapse that span into a small number of files you author and one command you run. The README frames it as packaging: you put serving logic in Python, and Truss handles containerization, dependency management, and GPU configuration. The quickstart goes further and shows a deployment with no Python at all, where config.yaml is the entire specification.

The audience is narrower than the tagline suggests. Truss is for people who have already chosen Baseten as the place their model runs. The README's own framing is explicit about this: Truss is the CLI for deploying and serving ML models on Baseten. If you are looking for a framework that produces a portable artifact you can hand to your own cluster, this is not that, and the quickstart makes the dependency concrete by requiring a Baseten account before anything else happens. What Truss removes is the undifferentiated work of writing a Dockerfile and wiring a serving harness. What it does not remove is the platform decision.

What actually happens between config.yaml and a running endpoint

The mechanism differs depending on which path you take, and the README only documents one of them in detail. In the engine path, config.yaml names a base model, a checkpoint repository, a sequence length, a quantization type, and a GPU count. The trt_llm block instructs Baseten to use Engine-Builder-LLM, which compiles the model with TensorRT-LLM. The README describes the sequence plainly: Baseten downloads the weights from Hugging Face, compiles them with TensorRT-LLM, and deploys the resulting container to an L4 GPU. Nothing in that sentence happens on your laptop. Your machine's job is to authenticate, read the config, and upload.

The second path is the model/ directory, which the README describes as the place for custom Python code when you need custom preprocessing, postprocessing, or unsupported model architectures. That is where the "write once, run anywhere" claim earns its keep, because the serving logic becomes yours rather than the engine's. The trade-off is visible in the same paragraph: the engine path supports live reload during development, and the README states directly that --watch is not supported for TRT-LLM. Compiled engines and fast iteration pull in opposite directions, and Truss resolves that by making you choose one before you start.

The commands and config keys the quickstart commits to

Installation is a single pip command, `pip install --upgrade truss`, though the quickstart prefers `uvx` so that Truss runs without a separate install step. Authentication comes first: `uvx truss login` opens an interactive picker offering either a pasted API key or a browser OAuth flow, and both can be forced with `uvx truss login --browser` or `uvx truss login --api-key "..."`. One detail in the README is easy to misread and worth repeating: setting BASETEN_API_KEY does not skip `truss login`. The key is what the OpenAI client sends later when calling the deployed model; it is not a substitute for the CLI's own authentication step.

Scaffolding is `uvx truss init qwen-2.5-3b`, which creates a config.yaml, a model/ directory, and supporting files. For engine deployments you edit only config.yaml. The documented keys for the Qwen example are model_name, resources.accelerator set to L4, resources.use_gpu set to true, and a trt_llm block containing build.base_model, build.checkpoint_repository.source and .repo, max_seq_len, quantization_type, tensor_parallel_count, and num_builder_gpus. Deployment is `uvx truss push`, which the README describes as a published deployment by default. The output includes a model ID, a deployment ID, an endpoint URL, and a logs link, and the model ID is what you substitute into the API call once the deployment shows Active.

The build-time GPU requirement is the constraint most likely to catch people out

The Qwen 2.5 3B example sets num_builder_gpus: 2 while the inference GPU is a single L4. The README explains why: fp8 quantization needs more GPU memory at compile time than at inference, and the first-model guide states that a single L4 can run out of memory during compilation without the second builder GPU. This is a real operational fact rather than a config detail. A 3B parameter model that fits comfortably at serving time can still fail to build on the hardware you picked for serving, and the failure happens before you have anything to call.

That asymmetry scales in an unpleasant direction. Larger checkpoints, longer max_seq_len values, and higher tensor_parallel_count all move the build cost, and the README does not give a table mapping model size to builder GPU count. You are left to discover the requirement by watching a build fail, which the logs link in the push output at least makes visible. There is also a scheduling consequence: if the build needs two GPUs that are only free at certain times, your deploy latency is governed by builder availability, not by how fast the weights download. The README does not discuss build queueing, so treat that as unverified.

Where Truss is the wrong tool

If your deployment target is not Baseten, the documented path does not apply. Every command in the quickstart assumes a Baseten account, a Baseten API key, and a push that lands on Baseten infrastructure. The README mentions deploying "to Baseten or your own infrastructure" in its production-readiness bullet, but the quickstart, the authentication flow, and the trt_llm engine block are all Baseten-shaped, and the supplied material does not describe what the self-hosted path looks like in practice. Anyone evaluating Truss as a general-purpose model server should treat that bullet as a claim to investigate rather than a documented workflow.

A second case is the one where you need live reload and a compiled engine at the same time. The README is blunt that --watch is not supported for TRT-LLM. If your development loop depends on editing serving code and seeing the change without a full rebuild, the engine path will not give you that, and you will be pushed toward the custom Python model/ path, which trades compile-time optimization for iteration speed. The README does not quantify that trade, so the size of the penalty is something you would have to measure on your own workload.

How this differs from writing your own FastAPI server and container

The obvious alternative is the one Truss is replacing: a Python HTTP server such as FastAPI or Flask, a Dockerfile that pins your CUDA base image and dependencies, and a deployment target you manage. That approach gives you full control over the request path, the batching strategy, and the runtime environment, and it produces an image that runs anywhere a container runs. It also means you own the CUDA version matrix, the image build, and the GPU scheduling, which is precisely the work the Truss quickstart avoids by handing the model to Engine-Builder-LLM.

A second alternative, for the narrow case of LLM serving, is running vLLM or SGLang yourself. The README lists both as engines Truss can deploy, so the choice is not Truss versus vLLM so much as who operates the vLLM process. Running it yourself keeps the serving stack in your own cluster and under your own upgrade cadence, and it means your artifact is a container you built rather than a config that a platform compiles. The difference in approach is where the optimization step lives: with Truss and the trt_llm block, compilation is a platform-side build step with its own GPU bill; with a self-managed vLLM container, you accept a less optimized runtime in exchange for a deployment you fully control. Neither is strictly better, and the README does not present benchmark comparisons between them.

Version cadence, licence, and what maintenance actually costs you

The release history shows tight iteration: v0.18.28, v0.18.29, and v0.18.30rc0 all landed within roughly a week of each other in early September 2026, and the repository's last push is dated 2026-09-09. Frequent patch releases on a 0.x line mean the CLI surface can shift, and the presence of a release candidate in the list suggests the project ships pre-releases alongside stable ones. If you pin Truss in CI, pin an exact version rather than a range, because the gap between v0.18.28 and v0.18.30rc0 is small in time and the config schema is the thing most likely to move.

Licensing is MIT, which is permissive and places few obligations on how you use the client. That is worth stating precisely, because MIT covers the code in the repository and not the services it talks to. Your relationship with Baseten, the terms under which your weights are stored and compiled, and the cost of builder GPUs are governed by the platform, not by the licence file. The supplied material does not include Baseten's pricing or terms, so the total cost of running the Qwen example cannot be estimated from this repository alone. The upgrade cost you can reason about is the config schema and the CLI flags; the cost you cannot is the platform bill.

Editorial conclusion

Adopt Truss if your serving target is Baseten and you want a config.yaml plus `uvx truss push` instead of a Dockerfile and a Kubernetes manifest. Do not adopt it if you need a vendor-neutral artifact you can run on your own scheduler, since the documented path assumes Baseten accounts, Baseten API keys, and Baseten-side compilation. Before committing, verify three things: whether your model architecture is covered by an engine or needs the model/ directory, whether your build fits the GPU memory that fp8 quantization demands at compile time (the README notes num_builder_gpus: 2 for a reason), and what the MIT licence on the client actually covers once your weights and build artifacts live on Baseten's side.

Official sources

  1. basetenlabs/truss on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes