The Builders' Lingua Franca
[![built with garnix](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgarnix.io%2Fapi%2Fbadges%2Fgarnix-io%2Fgarn)](https://garnix.io) [![](https://dcbadge.vercel.app/api/server/q2Fptb7My4?style=flat)](https://discord.gg/q2Fptb7My4) [![](https://img.shields.io/badge/library-v0.0.20-black)](https://doc.deno.land/https://garn.io/ts/v0.0.20/mod.ts) [![License](https://img.shields.io/github/license/garnix-io/garn)](LICENSE)
garn is a build tool and development environment manager. You configure your
project with a garn.ts
file that declaratively describes your project and its
dependencies.
You can think of it as coding up your README. Users, collaborators, and coworkers no longer need to manually follow install steps, or figure out what commands they can run, but instead can just use garn directly. And if it works for you, it works for everyone.[^1]
For example, with this garn.ts
file:
import * as garn from "https://garn.io/ts/v0.0.20/mod.ts";
export const frontend = garn.javascript.mkNpmProject({
description: "My project frontend",
src: "frontend",
nodeVersion: "18",
})
.addExecutable("run", "cd frontend && npm install && npm start");
export const backend = garn.go.mkGoProject({
description: "My project backend",
src: "backend",
goVersion: "1.21",
})
.addExecutable("run", "cd backend && go run ./main.go");
export const startAll = garn.processCompose({
frontend: frontend.run,
backend: backend.run,
});
Anyone can run your frontend with garn run frontend
, backend with garn run backend
, or both with garn run startAll
. All without needing to worry about
having the correct version of go
, nodejs
, or anything else installed.
You may have noticed the use of import URLs in the file above. This is supported by Deno, which we use under the hood. But you don't need to install that either. In fact, garn might just be one of the last things you have to manually install.[^2]
garn is powered by Nix, so you get portable and reproducible builds and development environments.
1) Install garn:
sh <(curl --proto '=https' --tlsv1.2 -sSf https://garn.io/install.sh)
garn
needs nix
to be installed, so if you don't
have nix already the above installer will install nix first, after asking
for confirmation.
garn edit
for that or, if you prefer, you can set up your own editor.
See this page for more information
2) Create your first garn.ts
file:
You can use garn init
to template out an initial configuration. You can
use garn edit
to start a text editor.
Check out the getting started guide for
more information on how to write and modify your garn.ts
file.
3) Run some things: Use the garn commands to run some tests, build packages, or run executables.
garn init
Running garn init
in a directory without a garn.ts
file will try to
automatically detect what kind of project you have and generate a garn.ts
file for you.
garn enter
garn enter [project or environment]
will put you in a development shell with
all needed dependencies available in your $PATH
.
garn build
garn build [project]
will build the specified project and create a symlink
named result
which links to the resulting build artifacts.
garn run
garn run [project]
will run the default executable for the specified project.
garn check
garn check [check]
will run all checks for the specified project. These
checks run in a sandbox. The downside of sandboxing is that these checks won't
have access to the internet. The upside is that they'll be (almost) perfectly
reproducible.
garn edit
garn edit
will start (and, if necessary, download) VSCodium, with Deno LSP
configured for you. It will open garn.ts
in the current directory. This won't
clobber any of your existing VSCode/VSCodium configuration and data.
Executable
s.Package
s, but where we don't care about the artifacts as much as the exit code.Environment
, so often can rely on dependencies that are not available "outside".Checks
, Packages
, Executable
s and Environment
s, or just adding new ones.
We currently have support for the Npm, Yarn, Go, and Haskell projects, with more languages coming soon. If you really want to see something, make your voice heard in our issue tracker!
Note also our examples directory, which contains tested examples of using garn in various ways.
All examples below require the two following imports:
import * as garn from "https://garn.io/ts/v0.0.20/mod.ts";
import * as pkgs from "https://garn.io/ts/v0.0.20/nixpkgs.ts";
All garn.ts
files require the first import, and often you also need the
second. Besides that, you rarely need other imports.
The basic workhorse of Npm projects is mkNpmProject
. An example:
export const frontend = garn.javascript.mkNpmProject({
description: "My project frontend",
src: ".",
nodeVersion: "18",
})
.withDevTools([pkgs.jq])
.addExecutable("run", "npm install && npm start")
.addCheck("test", "npm install && npm run test");
This creates a Project containing:
garn check frontend.test
)garn check frontend.test
).garn enter frontend
with all
dependencies available.The right version of node
, npm
, jq
, etc. will be used for all these.
You can see a full project here.
Go projects are usually built with mkGoProject
:
export const server = garn.go.mkGoProject({
description: "example backend server in go",
src: ".",
goVersion: "1.21",
})
.addExecutable("migrate", "go run ./scripts/migrate.go")
.addExecutable("dev", "go run ./main.go");
For creating Haskell projects, there's mkHaskellProject
. An example:
export const project = garn.haskell.mkHaskellProject({
description: "My project",
src: ".",
executables: ["server", "openapi-generation"]
ghcVersion: "ghc94"
})
Assuming you have a cabal
file in .
, this creates a Project containing:
garn build project
) that
includes the test-suites of your project.garn run project.server
and garn run project.openapi-generation
.garn enter project
with all
dependencies available.The right version of node
, npm
, jq
, etc. will be used for all these.
You can see a full project here.
The essential idea is to generate Nix code corresponding to your projects, and
then run Nix behind the scenes. In here,
you can see the simple but low-level Nix AST we use. Objects such as Check
s
have a nixExpression
field that contains their corresponding Nix expression.
garn then generates a flake.nix
that, for every exported variable of the garn.ts
file,
has a corresponding package
, check
, devshell
or app
.
This means that garn integrates with Nix (and the Nix ecosystem) both ways:
you can write pure Nix expressions and embed them in garn.ts
files, or import Nix projects, but
you can also from Nix call things generated by garn.
You can find documentation for the garn Deno library here.
Nix: Nix is a brilliant idea with an immense amount of volunteer effort behind it, and the giant's shoulders on which garn stands. It has a rather complex CLI, and the Nix language is a whole new thing to learn. That said it is a much more mature project with support for just about every imaginable stack. For complex projects, you might be better off picking Nix right now. For simpler ones, or ones that include collaborators who don't feel comfortable with Nix, garn might be a better option.
But the choice isn't exclusive
or binary: garn both allows including
Nix expressions or dependencies within it, and generates a flake.nix
file that
can be consumed by other Nix expressions, so that you can combine Nix and
garn quite well.
docker: Docker isolates processes, and is often used to distribute dev environments. garn overlaps with this feature. Both tools make it relatively certain that if it works once it works everywhere. But with Docker that comes at the price of harder integration with your development process.
Besides development environments, Docker is also used for other purposes, such as deployment. garn does not support any of that (yet).
[^1]: This might not always be true between different architectures and platforms (e.g. Linux vs. MacOS). [^2]: That said, the installation of garn itself isn't always smooth on MacOS. If you encounter a problem, please let us know.