{"id":16092282,"url":"https://github.com/alecthomas/bit","last_synced_at":"2026-04-11T22:29:06.405Z","repository":{"id":66600185,"uuid":"572917083","full_name":"alecthomas/bit","owner":"alecthomas","description":"Bit - A simple yet powerful build tool","archived":false,"fork":false,"pushed_at":"2025-03-13T02:23:00.000Z","size":861,"stargazers_count":12,"open_issues_count":10,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-13T03:24:16.525Z","etag":null,"topics":["build","build-tool"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alecthomas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["alecthomas"]}},"created_at":"2022-12-01T10:02:11.000Z","updated_at":"2025-01-27T03:09:50.000Z","dependencies_parsed_at":null,"dependency_job_id":"d353f4d1-974d-41eb-9b83-e8518570207a","html_url":"https://github.com/alecthomas/bit","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Fbit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Fbit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Fbit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Fbit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alecthomas","download_url":"https://codeload.github.com/alecthomas/bit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243871911,"owners_count":20361380,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["build","build-tool"],"created_at":"2024-10-09T16:06:37.586Z","updated_at":"2026-04-11T22:29:06.396Z","avatar_url":"https://github.com/alecthomas.png","language":"Go","funding_links":["https://github.com/sponsors/alecthomas"],"categories":[],"sub_categories":[],"readme":"# bit — Build It\n\nA declarative build tool with dependency tracking, content-based caching, and parallel execution.\n\nbit reads a `BUILD.bit` file, resolves dependencies between blocks, detects what changed, and only rebuilds what's needed. Language-aware providers (e.g. Go, Docker) automatically discover inputs from source files, so in most cases you don't need to specify them manually.\n\nLike Terraform, bit tracks the state of each block between runs. It detects drift (e.g. a deleted Docker image or stopped container), determines what actions are needed (create, update, replace, destroy), and applies only the minimum changes. `bit plan` shows what would change; `bit apply` makes it so; `bit destroy` tears it down.\n\n## Install\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/alecthomas/bit/main/install.sh | sh\n```\n\nOr from source:\n\n```sh\ncargo install --path .\n```\n\n## Quick Start\n\n```bit\n# Go inputs are auto-detected from source files\nserver = go.exe {\n  package = \"./cmd/server\"\n  output = \"dist/server\"\n}\n\nserver-linux = go.exe {\n  package = \"./cmd/server\"\n  output = \"dist/server-linux-arm64\"\n  cgo = false\n  goos = \"linux\"\n  goarch = \"arm64\"\n}\n\ntest = go.test {\n  package = \"./...\"\n  flags = [\"-race\"]\n}\n\nlint = go.lint {}\n\n# Docker auto-detects COPY/ADD sources and expands ARG/ENV vars\nimage = docker.image {\n  tag = \"myapp:latest\"\n  dockerfile = \"docker/Dockerfile\"\n  depends_on = [server-linux]\n}\n\n# bit tracks container state like Terraform — detects drift, replaces on config change\napp = docker.container {\n  image = image.ref\n  name = \"myapp\"\n  ports = [\"8080:8080\"]\n  healthcheck = \"curl -sf http://localhost:8080/health\"\n}\n\ntarget build = [server]\ntarget test = [test, lint]\ntarget deploy = [app]\n```\n\n```sh\nbit              # runs `apply` (default)\nbit plan         # show what would change\nbit apply build  # apply a specific target\nbit test         # run test blocks\nbit destroy      # remove outputs\nbit list         # list targets\nbit dump         # show evaluated inputs/outputs\n```\n\n## Language\n\n### Variables and Parameters\n\n```bit\nlet version = \"1.0.0\"\nlet git_sha = exec(\"git rev-parse --short HEAD\") | trim\n\nparam environment : string\nparam replicas : int = 1\n```\n\n### Blocks\n\n```bit\nname = provider.resource {\n  field = \"value\"\n  other = [1, 2, 3]\n}\n```\n\nSpecial fields:\n- `depends_on = [block, ...]` — content-coupled dependency (changes propagate)\n- `after = [block, ...]` — ordering-only dependency\n\nPrefix with `protected` to prevent replacement/destruction:\n\n```bit\nprotected db = docker.container { ... }\n```\n\n### Strings\n\nDouble-quoted with `${expr}` interpolation and heredocs:\n\n```bit\ngreeting = \"hello ${name}\"\nscript = \u003c\u003c-EOF\n  echo ${app.path}\n  echo \"done\"\nEOF\n```\n\n### Expressions\n\n```bit\nlist1 + list2           # list concatenation\na == b                  # equality / inequality\nexpr | trim             # pipes\nif cond then a else b   # conditionals\nfunc(arg1, arg2)        # function calls\nblock.field             # block output references\n```\n\n### Built-in Functions\n\n| Function | Description |\n|---|---|\n| `env(name)`, `env(name, default)` | Environment variable |\n| `exec(command)` | Run shell command, return stdout |\n| `glob(pattern)` | Expand filesystem glob |\n| `trim(value)` | Strip whitespace |\n| `lines(string)` | Split into lines |\n| `split(string, sep)` | Split by separator |\n| `uniq(list)` | Deduplicate list |\n| `secret(name)` | Access secret |\n\n### Targets and Outputs\n\n```bit\ntarget build = [app, lib]\noutput version = app.version\n```\n\n## Providers\n\n### exec\n\nGeneral-purpose shell commands.\n\n**`exec`** (build) — run a command, track inputs/outputs:\n```bit\napp = exec {\n  command = \"make build\"\n  output = \"bin/app\"       # single string or list\n  inputs = [\"src/**/*.c\"]  # glob patterns\n}\n```\n\n**`exec.test`** (test) — run a command, pass/fail by exit code:\n```bit\ntest = exec.test {\n  command = \"make test\"\n  inputs = [\"src/**/*.c\"]\n  format = \"ctrf\"          # optional: parse CTRF JSON from stdout\n  transform = \".results\"   # optional: jq expression for CTRF\n}\n```\n\n### go\n\nGo-aware provider with automatic input detection via source scanning (parses imports, `//go:embed`, `go.mod`/`go.sum`). Results are cached across blocks.\n\n**`go.exe`** — build a Go binary:\n```bit\napp = go.exe {\n  package = \"./cmd/app\"\n  output = \"dist/app\"      # optional, defaults to package base name\n  flags = [\"-ldflags=-s\"]  # optional\n  goos = \"linux\"           # optional\n  goarch = \"arm64\"         # optional\n  cgo = false              # optional\n}\n```\n\n**`go.build`** — compile without producing a binary:\n```bit\ncheck = go.build {\n  package = \"./...\"\n}\n```\n\n**`go.test`** — run tests:\n```bit\ntest = go.test {\n  package = \"./...\"\n  flags = [\"-timeout\", \"30s\", \"-race\"]\n}\n```\n\n**`go.lint`** — run `golangci-lint`:\n```bit\nlint = go.lint {}                  # defaults to ./...\nlint = go.lint { package = \"./cmd/app\" }\n```\n\n### docker\n\n**`docker.image`** — build a Docker image (auto-detects inputs from Dockerfile COPY/ADD):\n```bit\nimage = docker.image {\n  tag = \"myapp:latest\"\n  context = \".\"\n  dockerfile = \"Dockerfile\"\n  build_args = { VERSION = \"1.0\" }\n}\n```\n\n**`docker.container`** — run a Docker container:\n```bit\napp = docker.container {\n  image = image.ref\n  name = \"myapp\"\n  ports = [\"8080:8080\"]\n  volumes = [\"/data:/data\"]\n  environment = { DB_HOST = \"localhost\" }\n  healthcheck = \"curl -sf http://localhost:8080/health\"\n}\n```\n\n## How It Works\n\n1. Parse `BUILD.bit` and build a dependency DAG\n2. For each block in topological order:\n   - Evaluate field expressions (with upstream outputs in scope)\n   - Resolve input files via the provider\n   - Compute a content hash (file contents + dependency hashes)\n   - Skip if nothing changed; apply if inputs differ\n3. Persist state to `.bit/state/state.json`\n\nParallel execution with `-j N` (defaults to CPU count).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falecthomas%2Fbit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falecthomas%2Fbit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falecthomas%2Fbit/lists"}