Escape dependency hell.

Tangram is a programmable build system and package manager in which all dependencies are specified explicitly and pinned with a lockfile. You get the exact same versions of every package on every machine, so your builds are simple, reproducible, cacheable, and distributable.

Write your builds in JSON, JavaScript, or TypeScript.
Stop debugging errors caused by inconsistent package versions.
Stop building the same thing over and over again.
Transparently offload your builds to a cluster or the cloud.
Build a shell.

Create a tangram.json file at the root of your project and add some dependencies. Now run tg shell. This will create a tangram.lock file and drop you in a shell with your dependencies in $PATH. This is a great way to make sure everyone on your team is using the exact same versions of all the tools you need to work on your project.

// tangram.json { "dependencies": { "nodejs": "16.15.1", "postgresql": "14.4", "python": "3.10.4", "ripgrep": "13.0.0" } }
$ tg shell $ node --version v16.15.1 $ postgres --version postgres (PostgreSQL) 14.4 $ python --version Python 3.10.4 $ rg --version ripgrep 13.0.0
Build your code.

Use Tangram to build both your dependencies and your code. In this example, we build a Rust project and specify the exact version of the OpenSSL C library to link to.

export default { dependencies: { rust: "1.60", openssl: "3.0.4", }, }; export let build = () => { let { rust, openssl } = Tangram.dependencies; return rust.cargo({ source: Tangram.source, nativeDependencies: { "openssl-sys": [openssl()], }, }); };
Build a container.

Add a tangram.js file to the root of your project and use the std.buildContainerImage function to build a container image. In this example, we build a container image with a simple python project. Container image builds with Tangram are fast, reproducible, and minimal.

export default { dependencies: { python: "3.7", std: "^1", }, }; export let build = () => { let { python, std } = Tangram.dependencies; return std.buildContainerImage({ packages: [python()], command: "python", args: [Tangram.template`${Tangram.source}/`], }); };
Pin and patch dependencies.

Tangram packages come with a lot of options for customization. In this example, we build the Zig compiler at a particular revision from GitHub and apply a patch from an unmerged pull request. Now every machine that uses this shell will have the same custom build of Zig.

export default { dependencies: { std: "^1", zig: "0.9.0", }, }; export let shell = () => { let { std, zig } = Tangram.dependencies; let zigSource = std.fetchFromGitHub({ owner: "ziglang", repo: "zig", rev: "88d1258e08e668e620d5f8f4681315e555acbcd2", }); let zigPatch = std.fetch({ url: "", hash: "c0bb3d56ee8f34fb82bd4d64375b565601c62d9c2a289991fc9f088758ad86f8", }); return std.buildShell({ packages: [ zig({ source: zigSource, patches: [zigPatch], }), ], }); };
Try software without modifying your system.

Everything you build with Tangram is self contained and isolated from the rest of your system, so you can try software without affecting your other projects.

$ tg run ripgrep@13.0.0 -- --version ripgrep 13.0.0
Build and run on virtual machines.

Tangram has built-in virtualization so you can run builds and shells for other architectures and operating systems. Try the command below on macOS.

$ tg shell --system x86_64-linux -p coreutils -- uname -sm Linux x86_64