grafana/grafana
Patterns and conventions
Conventions that recur across the codebase. New code is expected to match.
Backend (Go)
Service-per-domain
Each business domain has a folder under pkg/services/<domain>/. The standard layout is:
pkg/services/<domain>/
├── <domain>.go # Service interface + types
├── <domain>impl/ # Concrete implementation
├── <domain>test/ # Test helpers / fakes
├── api/ # HTTP handlers (sometimes inlined into pkg/api/)
└── store/ # SQL queries (sometimes named `database/`)Services define their public surface as a Go interface; consumers depend on the interface, not the struct. Concrete implementations are wired in pkg/server/wire.go.
Wire DI
Adding a service is a four-step dance:
- Define the interface and constructor (
ProvideService(...)). - Add the constructor to the right
wire.NewSetinpkg/server/wire.go(or in a service-local wire set imported from there). - Inject the dependency where you need it.
- Run
make gen-goto regeneratewire_gen.go. Wire catches circular deps at codegen time, not at runtime.
Error handling
- Return
errutil.Errortypes from public APIs (pkg/util/errutil/) so they map cleanly to HTTP status codes. - Avoid bare
fmt.Errorffor user-visible errors — wrap in a typed error so the API layer can attach a status. - Don't swallow errors. If you can't handle, return.
Logging
log.New("<namespace>") is the canonical pattern. Namespaces are dotted (alerting.scheduler, secrets.gcp). Be specific so users can tune levels per area in [log.<namespace>].
Database access
- Legacy:
pkg/services/sqlstore/(xorm). New domain code increasingly hides this behind a domain-specific store interface. - Modern: app-platform resources go through
pkg/storage/unified/and the apiserver layer. - All migrations are forward-only and live in
pkg/services/sqlstore/migrations/. Adding one requires registering it in the migrator init and being aware of cross-database (SQLite/MySQL/Postgres) compatibility.
gRPC and plugins
Plugin communication and most internal cross-service streaming uses gRPC + protobuf. Protos live next to their implementations (e.g. pkg/storage/unified/resourcepb/). Regenerate with the appropriate make target.
Comments
From AGENTS.md: only add a comment when it explains why or surfaces non-obvious logic. No tracking links (Slack/Jira/GitHub) inside code.
Frontend (TypeScript / React)
Redux Toolkit and RTK Query
- Use Redux Toolkit slices, not the legacy
connect-style reducers. - Server state lives in RTK Query APIs (per-feature
<feature>Api.tsfiles). Local UI state lives in slices. - Action types and selectors are typed via slice exports; avoid string literals.
Components
- Function components with hooks. No class components in new code.
- Style with Emotion via
useStyles2(getStyles). ThegetStylesfunction takes the theme. - Use components from
@grafana/ui(Button, Field, Select, Stack, …) instead of building your own primitives.
File and naming conventions
- Component file:
MyThing.tsx. Test:MyThing.test.tsx. Hook:useMyThing.ts. Constant/enum:myThing.types.tsorconstants.tsadjacent to use. - Feature folders under
public/app/features/<feature>/typically containstate/(slice / api),components/,pages/,hooks/, andtypes.ts. - Avoid default exports for components — named exports keep refactors easier.
i18n
- Strings rendered in the UI go through
<Trans>(children) ort()(programmatic) from@grafana/i18n. - After adding new strings, run
make i18n-extractto update the extracted catalog. - The repo does not accept community-submitted translations of
grafana.jsonfiles; only the marking of strings.
Theming
- All colors and tokens come from the active theme (
theme.colors.*,theme.shape.*,theme.typography.*). Don't hard-code colors. - A custom ESLint rule (
@grafana/theme-token-usage) flags raw color literals in some areas.
Plugin extension points
- New extension points for plugins go through
@grafana/runtime'susePluginExtensions/usePluginLinks. Add the correspondingaddedComponents/addedLinksdeclaration in your plugin'splugin.json.
Cross-cutting
Feature toggles
- Add toggles in
pkg/services/featuremgmt/registry.go, then runmake gen-feature-toggles. - In Go:
features.IsEnabled(ctx, "myToggle"). In TS:config.featureToggles.myToggle. - Mark the stage (
Experimental,PrivatePreview,PublicPreview,GA,Deprecated) — new toggles default to Experimental.
Schema changes
- CUE definitions in
kinds/generate Go and TS. Edit the CUE, runmake gen-cue, commit the regenerated outputs alongside the source change. - App-platform schemas under
apps/<name>/kinds/generate viamake gen-apps.
Security defaults
- Treat all user input as untrusted. The codebase has dedicated escapers for SQL (sqlstore), shell (none — avoid shelling out), and HTML (
@grafana/datatextUtil). - Don't log secrets. Helpers in
pkg/services/secrets/wrap encryption. - Frontend XSS: never
dangerouslySetInnerHTMLuser content; use<SanitizedHtml>or the safe textUtil helpers.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.