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.

Simple
Write your builds in TypeScript with autocomplete and type checking.
Reproducible
Stop debugging errors caused by inconsistent package versions.
Cacheable
Stop building the same thing over and over again.
Distributable
Transparently offload your builds to a cluster or the cloud.
Build a shell.

Create a file named tangram.tg at the root of your project with the code below and 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.

import nodejs from "tangram:nodejs@16.15.1"; import postgresql from "tangram:postgresql@14.4"; import * as std from "tangram:std"; export let shell = tg.createTarget(({ target }) => std.shell({ dependencies: [ nodejs({ target }), postgresql({ target }), ] }));
$ tg shell $ node --version v16.15.1 $ postgres --version postgres (PostgreSQL) 14.4 $ exit
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 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.

import { cargo } from "tangram:rust@1.60.0"; import openssl from "tangram:openssl@3.0.0"; export default ({ system }) => { return rust.cargo({ system, source: import.meta.source, nativeDependencies: { "openssl-sys": [openssl({ system })], }, }); };
Build a container.

Use the 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.

import * as python from "tangram:python"; import * as std from "tangram:std"; export let build = () => { return std.buildContainerImage({ packages: [python()], command: "python", args: [t`${import.meta.source}/main.py`], }); };
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.

import * as zig from "tangram:zig"; export let shell = () => { let zigSource = std.downloadFromGitHub({ owner: "ziglang", repo: "zig", rev: "88d1258e08e668e620d5f8f4681315e555acbcd2", }); let zigPatch = tg.download({ url: "https://github.com/ziglang/zig/pull/9771.patch", checksum: std.sha256("c0bb3d56ee8f34fb82bd4d64375b565601c62d9c2a289991fc9f088758ad86f8"), }); return std.shell({ packages: [ zig({ source: zigSource, patches: [zigPatch], }), ], }); };