Map

ultimate-gojust

Toolbox toolboxgolangbuild-automationjustJustMIT โ†ณ show in map Markdown
title
ultimate-gojust
type
toolbox
summary
Drop-in Justfile covering Go build, cross-compile, lint, hot reload and database migrations
tags
golang, build-automation, just
language
Just
license
MIT
created
2026-04-07
updated
2026-04-07

A drop-in Justfile that covers the full Go project lifecycle: project scaffolding, building with version injection, cross-compilation, testing with coverage, linting, security scanning, hot reload, Docker, and database migrations. It's the just-based sibling of ultimate-gomake (same author, same features, different runner).

How it works

The justfile is a single file you copy into your project root. It uses just's env_var_or_default() for a configuration cascade: CLI args override env vars, which override .env file values, which override hardcoded defaults. This means you can do just GOOS=darwin build without editing anything.

Version embedding

The build recipe automatically extracts version info from git and injects it via ldflags:

version := `git describe --tags --always --dirty 2>/dev/null || echo "dev"`
git_commit := `git rev-parse --short HEAD 2>/dev/null || echo "unknown"`

ld_flags := "-s -w \
    -X '$(go list -m)/pkg/version.Version=" + version + "' \
    -X '$(go list -m)/pkg/version.Commit=" + git_commit + "' \
    -X '$(go list -m)/pkg/version.Branch=" + git_branch + "' \
    -X '$(go list -m)/pkg/version.BuildTime=" + build_time + "' \
    -X '$(go list -m)/pkg/version.BuildBy=" + build_by + "'"

This expects a pkg/version package with exported string vars. The -s -w flags strip debug info and DWARF tables for smaller binaries.

Cross-compilation

The build-all recipe loops over seven OS/arch combinations (linux amd64/arm64/armv7, darwin amd64/arm64, windows amd64/arm64), builds static binaries with CGO_ENABLED=0, and tarballs each output. The Windows builds get .exe suffixed automatically.

Dev tooling

just deps installs golangci-lint, gofumpt, govulncheck, mockgen, and Air (hot reloader). just dev downloads an Air config if missing and starts watching for changes. just lint runs golangci-lint with --fix. just security runs govulncheck.

Database migrations

Uses golang-migrate with PostgreSQL and MySQL support. just db-migrate runs pending migrations, just db-rollback reverts one step, just db-reset drops everything. All read DATABASE_URL from the environment.

Entrypoint convention

The repo assumes main/main.go as the build entrypoint, which is uncommon โ€” the standard Go convention is cmd/<name>/main.go for projects with one or more binaries. The build recipe would need adjustment for cmd/ layouts:

build:
    mkdir -p {{bin_dir}}
    {{go}} build \
        -ldflags '{{ld_flags}}' \
        -o {{bin_dir}}/{{project_name}} \
        ./cmd/{{project_name}}

For multi-binary projects, you'd loop over directories under cmd/.

Interesting patterns to borrow

The most reusable parts for any Go Justfile:

  • ldflags version injection โ€” wire git metadata into binaries at compile time, no code generation needed
  • Configuration cascade via env_var_or_default() โ€” makes the same Justfile work across dev, CI, and production without forks
  • Cross-compile loop โ€” a compact way to produce release binaries for all platforms
  • Tool pinning via go install ...@latest in a deps recipe โ€” keeps the team on the same toolchain

Limitations

  • Single-binary only โ€” no built-in support for cmd/ multi-binary layouts
  • Tool versions pinned to @latest rather than specific versions, which can cause CI flakiness
  • The init recipe downloads a .gitignore from gitignore.io (an external dependency that may go away)
  • No Makefile equivalent included in this repo (but ultimate-gomake exists separately)

49 stars, MIT license. Repo: https://github.com/binbandit/ultimate-gojust