> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/temporalio/temporal/llms.txt
> Use this file to discover all available pages before exploring further.

# Development Best Practices

> Best practices and guidelines for contributing to Temporal Server

This guide covers best practices and conventions for developing Temporal Server.

## Code Style

### Follow Project Conventions

<Warning>
  Rigorously adhere to existing project conventions. Always analyze surrounding code, tests, and configuration before making changes.
</Warning>

Key principles:

* Mimic the style (formatting, naming), structure, and architectural patterns of existing code
* Understand local context (imports, functions, interfaces) to ensure changes integrate naturally
* Never introduce new patterns without discussing with maintainers

### Comments

Add comments sparingly. Focus on **why** something is done, not **what** is done:

```go theme={null}
// Good: Explains why
// Use buffered channel to prevent goroutine leak if context is cancelled
ch := make(chan result, 1)

// Bad: Explains what (obvious from code)
// Create a channel for results
ch := make(chan result, 1)
```

For future design considerations, use:

```go theme={null}
// CONSIDER(username): We might want to batch these operations for better performance
```

### Formatting

Use the project's formatting tools:

```bash theme={null}
# Format imports
make fmt-imports

# Run go fix
make fmt-gofix

# Format YAML files
make fmt-yaml

# Format everything
make fmt
```

## Error Handling

### Always Handle Errors

<Warning>
  Errors MUST be handled, never ignored.
</Warning>

```go theme={null}
// Good
if err := doSomething(); err != nil {
    return fmt.Errorf("failed to do something: %w", err)
}

// Bad - DO NOT DO THIS
_ = doSomething()
doSomething() // Ignored error
```

### Logging Errors

Use appropriate logging methods based on severity:

```go theme={null}
// For core invariant violations that should never happen
logger.Fatal("invariant violation", tag.Error(err))

// For important issues that shouldn't crash production
logger.DPanic("unexpected state", tag.Error(err))

// For expected errors
logger.Warn("operation failed, will retry", tag.Error(err))
```

### Wrapping Errors

Provide context when wrapping errors:

```go theme={null}
if err := updateDatabase(ctx, record); err != nil {
    return fmt.Errorf("update database for workflow %s: %w", workflowID, err)
}
```

## Testing Best Practices

### Write Tests for New Functionality

All new features require tests covering:

* Best-case scenarios
* Failure modes
* Edge cases
* Error handling

### Test Organization

```go theme={null}
func TestFeatureName(t *testing.T) {
    t.Parallel() // Always use parallel unless there's a reason not to
    
    tv := testvars.New(t) // Use testvars for test data
    
    // Test setup
    s := testcore.NewEnv(t)
    
    // Test execution
    // ...
    
    // Assertions
    require.NoError(t, err) // Prefer require over assert
}
```

### Prefer `require` Over `assert`

```go theme={null}
// Good: Stops test immediately on failure
require.NoError(t, err)
require.Equal(t, expected, actual)

// Avoid: Continues test after failure (can cause panics)
assert.NoError(t, err)
assert.Equal(t, expected, actual)
```

### Avoid Testify Suites in Unit Tests

Testify suites are required for functional tests but should be avoided in unit tests:

```go theme={null}
// Good: Simple table-driven unit test
func TestValidation(t *testing.T) {
    t.Parallel()
    tests := []struct{
        name string
        input string
        want error
    }{
        // test cases
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            t.Parallel()
            got := Validate(tt.input)
            require.Equal(t, tt.want, got)
        })
    }
}

// Functional tests can use testcore.NewEnv
func TestWorkflowExecution(t *testing.T) {
    s := testcore.NewEnv(t)
    // ...
}
```

### Use `require.Eventually` Instead of `time.Sleep`

```go theme={null}
// Good: Wait for condition with timeout
require.Eventually(t, func() bool {
    return taskCompleted.Load()
}, 5*time.Second, 100*time.Millisecond)

// Bad: Hardcoded sleep (forbidden by linter)
time.Sleep(5 * time.Second)
require.True(t, taskCompleted.Load())
```

### Run Tests After Changes

```bash theme={null}
# Start with unit tests (fastest)
make unit-test

# Run relevant integration tests
go test -v -tags test_dep ./common/persistence/tests -run TestYourChange

# Run full test suite before submitting PR
make test
```

## Dependency Management

### Never Assume Libraries Are Available

<Warning>
  Do not introduce new third-party libraries unless specifically requested or approved by maintainers.
</Warning>

Before using any library:

1. Check if it exists in `go.mod`
2. Look for existing usage patterns in the codebase
3. Verify it's appropriate for the use case

### Updating Dependencies

```bash theme={null}
# Update API dependencies
make update-go-api

# Update minor versions
make update-dependencies

# Check for major version updates
make update-dependencies-major

# Clean up
make gomodtidy
```

## Code Generation

### When to Regenerate Code

Regenerate code after modifying:

**Proto files:**

```bash theme={null}
make proto
```

**Files with `//go:generate` directives:**

```bash theme={null}
make go-generate
```

**Example `//go:generate` directive:**

```go theme={null}
//go:generate mockgen -package mocks -destination mocks/interface.go . Interface
```

### Verify Generated Code

After regenerating code:

```bash theme={null}
# Check for uncommitted changes
git status

# Verify all code regenerated properly
make ensure-no-changes
```

## Linting and Validation

### Run Linters Before Committing

```bash theme={null}
# Lint Go code
make lint-code

# Lint proto definitions
make lint-protos

# Lint GitHub Actions
make lint-actions

# Lint YAML files
make lint-yaml

# Run all linters
make lint
```

### Fix Linting Issues

Many linting issues can be auto-fixed:

```bash theme={null}
# Fix import formatting
make fmt-imports

# Fix YAML formatting
make fmt-yaml

# Apply go fix rules
make fmt-gofix
```

### Breaking Changes

Verify proto changes don't break compatibility:

```bash theme={null}
make buf-breaking
```

## License Headers

All source files require license headers. Verify:

```bash theme={null}
make copyright
```

## Commit Messages

Follow the [Chris Beams guide](http://chris.beams.io/posts/git-commit/) for commit messages:

1. Separate subject from body with a blank line
2. Limit subject line to 50 characters
3. Capitalize the subject line
4. Do not end the subject line with a period
5. Use imperative mood ("Add feature" not "Added feature")
6. Wrap body at 72 characters
7. Use body to explain **what** and **why**, not **how**

**Example:**

```
Add workflow update validation

Validate update requests before processing to prevent invalid state
transitions. This fixes a race condition where concurrent updates
could corrupt workflow state.

Fixes #1234
```

## Pull Request Titles

PR titles should:

* Start with an uppercase letter
* Have no period at the end
* Not use generic titles like "bug fixes" or "updates"
* Clearly describe the change

**Good PR titles:**

* "Add validation for workflow update requests"
* "Fix race condition in history service shutdown"
* "Improve performance of task queue matching"

**Bad PR titles:**

* "bug fixes"
* "updates."
* "fix stuff"

## Project Structure

Understand the project layout:

* `/api` - Proto definitions and generated code
* `/chasm` - Chasm library (Coordinated Heterogeneous Application State Machines)
* `/client` - Client libraries for inter-service communication
* `/cmd` - CLI commands and main applications
* `/common` - Shared modules across all services
  * `/common/dynamicconfig` - Dynamic configuration
  * `/common/membership` - Cluster membership
  * `/common/metrics` - Metrics definitions
  * `/common/namespace` - Namespace cache
  * `/common/persistence` - Persistence layer
* `/components` - Nexus components
* `/config` - Configuration files
* `/proto` - Internal proto definitions
* `/schema` - Database schemas
* `/service` - Main services
  * `/service/frontend` - Frontend service
  * `/service/history` - History service
  * `/service/matching` - Matching service
  * `/service/worker` - Worker service
* `/tests` - Functional tests

## Important Make Targets

### Common Commands

```bash theme={null}
# Build everything and run all checks
make all

# Install dependencies and build binaries
make install

# Build just the binaries
make bins

# Clean all build artifacts
make clean
```

### Development Workflow

```bash theme={null}
# 1. Make your changes

# 2. Format code
make fmt-imports

# 3. Regenerate if needed
make proto          # If you modified .proto files
make go-generate    # If you modified //go:generate files

# 4. Run tests
make unit-test

# 5. Run linters
make lint-code

# 6. Commit your changes
git add .
git commit -m "Your commit message"
```

### CI Build Steps

The CI runs these checks:

```bash theme={null}
make ci-build-misc
```

This includes:

* Proto compilation
* Code generation
* Breaking change detection
* Shell script checking
* Import formatting
* Go mod tidy
* Verification that all generated code is committed

## Debugging

### Running Server Locally

Start the server with different persistence options:

```bash theme={null}
# SQLite (default, no dependencies required)
make start

# SQLite with persistent file
make start-sqlite-file

# Cassandra + Elasticsearch
make start-dependencies
make install-schema-cass-es
make start-cass-es

# PostgreSQL
make start-dependencies
make install-schema-postgresql
make start-postgresql

# MySQL
make start-dependencies
make install-schema-mysql
make start-mysql
```

### IDE Debugging (GoLand)

To debug the server:

1. Set Run Type to "package"
2. Package path: `go.temporal.io/server/cmd/server`
3. Program arguments:
   ```
   --env development-sqlite --allow-no-auth start
   ```

For other databases:

```
--env development-postgres12 --allow-no-auth start
--env development-mysql8 --allow-no-auth start
--env development-cass-es --allow-no-auth start
```

See [GoLand Debugging documentation](https://www.jetbrains.com/help/go/debugging-code.html) for details.

## Contributor License Agreement

All contributors must sign the [Temporal Contributor License Agreement](https://github.com/temporalio/temporal/blob/main/docs/development/temporal-cla.md) before we can merge changes.

## Getting Help

* [Temporal Community Forum](https://community.temporal.io)
* [Temporal Slack](https://t.mp/slack)
* [GitHub Discussions](https://github.com/temporalio/temporal/discussions)
* [Proposal Process](https://github.com/temporalio/proposals) for new features

## Additional Resources

* [Architecture Documentation](https://github.com/temporalio/temporal/tree/main/docs/architecture)
* [Testing Documentation](https://github.com/temporalio/temporal/blob/main/docs/development/testing.md)
* [OpenTelemetry Tracing](https://github.com/temporalio/temporal/blob/main/docs/development/tracing.md)
* [Adding New RPCs](https://github.com/temporalio/temporal/blob/main/docs/development/new-rpcs.md)
