Open-Source Wikis

/

CockroachDB

/

How to contribute

/

Patterns and conventions

cockroachdb/cockroach

Patterns and conventions

Coding idioms that recur across the CockroachDB tree. The canonical style guide is docs/style.md.

Formatting

Always run crlfmt -w -tab 2 path.go after editing a Go file. It enforces 100-column code lines, 80-column comment lines, CRDB import grouping (stdlib / cockroachdb / others), and CRDB long-signature wrapping. It is not gofmt. Imports are auto-grouped on save by most editor integrations; otherwise crlfmt does it.

Errors

CockroachDB uses github.com/cockroachdb/errors everywhere. Key guidelines:

  • Wrap with errors.Wrapf(err, "context %s", arg) to add context.
  • Use errors.Is/errors.As for sentinel checks.
  • Mark errors as redactable when they may carry user data: errors.Newf(...) is preferred over fmt.Errorf because it captures redactable arguments.
  • Errors that cross network boundaries must be encodable: see errors.EncodeError.

For CockroachDB-specific error types, see pkg/sql/sqlerrors/, pkg/server/srverrors/, and pkg/kv/kvpb/errors.go.

Logging

Use pkg/util/log rather than log from the standard library:

log.Infof(ctx, "starting replica %d", repl.RangeID)
log.VEventf(ctx, 2, "lock %s acquired by %s", key, txn.ID)
log.Errorf(ctx, "fatal error: %+v", err)

%+v prints redactable arguments in their unredacted form; %v prints them with redaction markers. Always pass a context.Context so the logger can attach span info.

Verbose logging is gated by V-levels: prefer log.VEventf (which is also a tracing event) over log.V(2).Infof for new code.

Cluster-version gating

Any backwards-incompatible behavior must be gated on a cluster version. The pattern:

if !cv.IsActive(ctx, clusterversion.V25_4FooNew) {
    // legacy path
    return legacy()
}
return newPath()

Add the version to pkg/clusterversion/cockroach_versions.go and write a migration in pkg/upgrade/upgrades/ if the upgrade is more than a feature toggle. See systems/cluster-version-and-upgrade.

Cluster settings

Runtime knobs live in pkg/settings/:

var fooEnabled = settings.RegisterBoolSetting(
    settings.SystemVisible,
    "kv.foo.enabled",
    "whether foo is enabled",
    true,
)

Use the right Class: SystemOnly for host-only knobs, TenantWritable for per-tenant overrides, SystemVisible for read-only-from-tenant. Documented in docs/configuration.md.

Concurrency

CockroachDB has a few non-obvious primitives:

  • syncutil.Mutex in pkg/util/syncutil/ — a sync.Mutex with deadlock detection in race builds.
  • stop.Stopper in pkg/util/stop/ — owns goroutine lifecycles. Always launch goroutines with stopper.RunAsyncTask (or RunTask) to ensure they participate in shutdown.
  • ctxgroup in pkg/util/ctxgroup/ — like errgroup, but cancellation-aware.
  • quotapool in pkg/util/quotapool/ — generic resource quota.

Never call go fn() in production code. Goroutines must be tracked.

Context propagation

Pass context.Context as the first argument to nearly every function (a few hot-path KV functions accept it as a separate field for performance). The context carries the trace span, logging tags, and cancellation. When you need to derive a new tag, use logtags.AddTag(ctx, "k", v).

Protobuf and wire compatibility

When changing a proto:

  • Never change a field's tag number.
  • Removing a field requires reservation: reserved 5.
  • Renaming a field is fine on the wire but breaks Go callers — coordinate.
  • Add a // keep comment in BUILD.bazel for proto-only deps that gazelle would otherwise drop.

pkg/clusterversion/ gates the use of new wire fields when older nodes might still be in the cluster.

Tests

  • Use table-driven tests where appropriate (docs/style.md has examples).
  • Datadriven tests are encouraged for compiler-style code (parser, optimizer, MVCC).
  • defer leaktest.AfterTest(t)() at the start of any test that spawns goroutines.
  • Tests should not depend on time.Now() directly; use hlc.NewClockForTesting.
  • Build skip directives (skip.UnderRace, skip.UnderStress, skip.UnderShort) explicit and explained.

Naming

  • Exported types/functions get GoDoc starting with the symbol name (// Foo does …).
  • Test functions: TestSomething, BenchmarkSomething, ExampleSomething. Sub-tests use t.Run("name", ...).
  • Files implementing one type/feature: name them after the type/feature (replica_send.go).
  • Avoid stuttering: kvserver.Store, not kvserver.KVServerStore.

Comments

Comments add depth, not repetition. From CLAUDE.md:

CockroachDB is a complex system. Write code under the assumption that future readers have basic familiarity but are not experts. Explain key concepts and abstractions, state lifecycles and ownership, use examples, and don't repeat the code in comments.

Release notes

User-visible changes need a release-note line in the commit body:

Release note (sql change): foo now supports bar.
Release note (bug fix): fixed crash when …
Release note (none)

The bot enforces the format and rejects PRs without one.

Imports

Import alphabetical order, grouped:

  1. stdlib
  2. github.com/cockroachdb/... packages
  3. third-party

crlfmt will reformat imports for you.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – CockroachDB wiki | Factory