Standard configurations, workflows, and templates for consistent, secure Go projects.
Most tools (golangci-lint, pre-commit, GitHub Actions, editors) require config files to live inside the consuming repository. There is no way around copying those files. However, Renovate supports shared presets that can be referenced from a single line — so you get central control without copying.
| Method | Files | What it means |
|---|---|---|
| Reference (single source of truth) | Renovate config | Your project's renovate.json contains one extends line pointing here. Changes to the preset take effect everywhere automatically. |
| Copy (into each repo) | Everything else | Tools require these files locally. Copy them once, then customize TODO: markers. Renovate keeps the SHA-pinned action versions up to date. |
| File | Purpose |
|---|---|
.editorconfig |
Consistent editor settings (tabs for Go, spaces for YAML/JSON, LF line endings) |
.gitattributes |
Consistent line endings and binary file handling |
.gitignore |
Standard Go ignores (binaries, test artifacts, IDE files, dist/) |
.golangci.yml |
Balanced golangci-lint v2 config (errcheck, govet, gosec, revive, and more) |
.goreleaser.yml |
Cross-platform release builds — only for CLI projects |
.pre-commit-config.yaml |
Pre-commit hooks: gitleaks, golangci-lint, whitespace, YAML check |
.yamllint.yml |
YAML linting rules (120 char warning, truthy values, comments) |
The shared Renovate preset lives in default.json in this repository.
Do not copy it. Instead, put this minimal renovate.json in your project:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"github>TomTonic/go-project-defaults"
]
}That single extends line pulls in the full config: automerge rules,
grouping, commit message format, vulnerability alerts, and more.
Any change to default.json in this repo takes effect across all
projects on the next Renovate run.
You can override any setting in your project's renovate.json:
{
"extends": ["github>TomTonic/go-project-defaults"],
"schedule": ["after 10pm"],
"packageRules": [
{
"description": "Project-specific: pin this dependency",
"matchPackageNames": ["example.com/some-lib"],
"allowedVersions": "<2.0.0"
}
]
}A ready-to-copy example is provided as renovate.json in this repository.
| File | Trigger | Purpose |
|---|---|---|
ci.yml |
push, PR | Lint (golangci-lint) + go mod tidy check + test with race detector |
coverage.yml |
push | Test coverage with gist-based badge (no dead branch!) |
codeql.yml |
push to main, PR, weekly | GitHub CodeQL security analysis |
dependency-review.yml |
PR | Flag known-vulnerable dependencies in PRs |
scorecard.yml |
push to main, weekly | OpenSSF Scorecard supply-chain audit |
grype-me.yml |
daily, manual | Vulnerability scan via grype_me with badge |
fuzz.yml |
manual (schedule disabled) | Go fuzz testing for all Fuzz* targets |
release.yml |
version tag (v*) |
GoReleaser binary builds — only for CLI projects |
| File | Purpose |
|---|---|
SECURITY.md |
Vulnerability reporting instructions (GitHub private reporting) |
CONTRIBUTING.md |
Contribution guidelines, commit conventions, testing standards |
AGENTS.md |
AI coding assistant guidelines (Codex, Claude, etc.) |
.github/copilot-instructions.md |
GitHub Copilot-specific project instructions |
- Renovate: Add
renovate.jsonwith the one-lineextendsreference (see Renovate section above). Done — no copying needed. - Everything else: Copy the files you need into your Go project.
- Search for
TODO:comments and customize (project name, thresholds, paths). - Set up required secrets and variables (see below).
- Let Renovate run once — it will pin any unpinned action tags to SHAs.
All badges use gist-based storage — no dead branches, no external services. You can reuse a single gist for all badges across all your projects.
- Create a GitHub Gist at gist.github.com with any initial file (e.g.
init.txtcontaining{}). - Create a PAT at GitHub Settings → Tokens with
gistscope. - Add to each repository:
| Type | Name | Value | Used by |
|---|---|---|---|
| Secret | GIST_TOKEN |
Your gist PAT | coverage, grype_me |
| Variable | COVERAGE_GIST_ID |
Gist ID | coverage.yml |
| Variable | GRYPE_BADGE_GIST_ID |
Gist ID (can be the same) | grype-me.yml |
Coverage:
[](https://gist.github.com/<USER>/<GIST_ID>)Vulnerabilities:
[](https://gist.github.com/<USER>/<GIST_ID>#file-<REPO>-grype-md)Replace <USER>, <GIST_ID>, and <REPO> with your values.
The shared preset (default.json) automerges patch and minor updates
when CI is green. This is a good balance for most Go projects — the Go
ecosystem has strong backward compatibility guarantees.
To switch a specific project to a more conservative strategy (patches only,
manual review for minor), add overrides in that project's renovate.json:
{
"extends": ["github>TomTonic/go-project-defaults"],
"packageRules": [
{
"matchUpdateTypes": ["minor"],
"automerge": false,
"reviewersFromCodeOwners": true
}
]
}The preset's automerge rule still applies to patches; the project-level override disables it for minor updates only.
Default: 80%. Change the COVERAGE_THRESHOLD env variable in
.github/workflows/coverage.yml.
The fuzz workflow is disabled by default (manual trigger only). To enable scheduled runs:
- Make sure your project has fuzz tests (
func FuzzXxx(f *testing.F)). - Uncomment the
scheduletrigger in.github/workflows/fuzz.yml. - Adjust
FUZZ_TIMEto control how long each target runs.
The .goreleaser.yml and release.yml workflow are for CLI tools that produce
binaries. Libraries don't need these — just use git tags.
Customize .goreleaser.yml:
- Set
project_name. - Adjust
goos/goarchfor your target platforms. - Modify
ldflagsto match your version variables.
| Skip if... | Files |
|---|---|
| Library (no binaries) | .goreleaser.yml, .github/workflows/release.yml |
| No fuzz tests | .github/workflows/fuzz.yml |
| No AI agent interaction expected | AGENTS.md |
- SHA-pinned actions with version comments. Renovate updates these automatically.
step-security/harden-runnerin every workflow for supply-chain hardening.- Go version from
go.mod(go-version-file) — no version duplication. - Gist-based badges instead of branch-based — no dead
badgesbranch cluttering your repo. katexochen/go-tidy-checkin CI catches forgottengo mod tidy.- golangci-lint v2 config with shadow detection, gosec, revive, and gocritic — strict enough to catch real problems, relaxed enough not to annoy.
grype_meruns daily againstlatest_releasefor continuous vulnerability monitoring.