Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/traefik/traefik/llms.txt

Use this file to discover all available pages before exploring further.

Contribution Guidelines

This guide covers the standards and best practices for contributing code to Traefik. Following these guidelines helps ensure your contributions can be reviewed and merged quickly.

Before You Start

Create an Issue First: For enhancements or features, always create an issue before starting work. This allows maintainers to provide design feedback and confirm the feature aligns with project goals.

Check Existing Work

Before starting:
  1. Search existing issues to avoid duplicates
  2. Comment on issues you’re interested in working on
  3. Look for the contributor/wanted tag for priority features
  4. Check Good First Issues if you’re new

Development Workflow

1. Fork and Clone

Fork the repository and clone it locally:
git clone https://github.com/YOUR_USERNAME/traefik.git
cd traefik
git remote add upstream https://github.com/traefik/traefik.git

2. Create a Branch

Create a feature branch from the latest master:
git checkout master
git pull upstream master
git checkout -b feature/my-contribution
Branch Naming: Use descriptive names like fix/issue-1234 or feature/add-retry-middleware.

3. Make Changes

Write your code following the standards below.

4. Commit Changes

Write clear, descriptive commit messages:
git commit -m "Add retry middleware for HTTP requests

Implements exponential backoff with configurable max attempts.
Fixes #1234"

Commit Message Best Practices

  • Subject line: 50 characters or less, imperative mood (“Add” not “Added”)
  • Body: Explain the “why” not the “what”
  • Reference issues: Include Fixes #123 or Relates to #456
  • Sign commits: Use git commit -s if required
Resources:

5. Push Changes

git push origin feature/my-contribution

6. Create Pull Request

Open a pull request from your fork to traefik:master.

Code Standards

Go Style

Traefik follows standard Go conventions with additional linting rules:

Formatting

  • Use gofumpt (stricter than gofmt)
  • Run make fmt before committing
  • Organize imports with gci
make fmt

Linting

All code must pass golangci-lint:
make lint
Key linters enabled:
  • govet - Go vet checks
  • errcheck - Verify error handling
  • gofumpt - Strict formatting
  • gci - Import organization
  • staticcheck - Advanced static analysis
  • gosimple - Simplification suggestions
  • ineffassign - Detect ineffectual assignments
  • unparam - Unused function parameters
See .golangci.yml in the repository root for the complete linter configuration.

Code Organization

  • Package names: Short, lowercase, no underscores
  • Function names: Clear and descriptive (prefer CreateHandler over CH)
  • Variable names: Short for small scopes, descriptive for larger scopes
  • Interfaces: Name with -er suffix when appropriate (Reader, Writer)

Comments

Comment Everything: We work internationally and cross-culturally. Comment all changes thoroughly so reviewers understand your intent and strategy.

Required Comments

  • Exported functions/types: Must have doc comments
  • Complex logic: Explain the “why” behind non-obvious code
  • TODOs: Use // TODO: description (but avoid in production code)
  • Package comments: Document package purpose in doc.go or main file
Example:
// CreateRetryMiddleware creates a middleware that retries failed requests
// using exponential backoff. It returns an error if maxAttempts is less than 1.
func CreateRetryMiddleware(maxAttempts int) (Middleware, error) {
    if maxAttempts < 1 {
        return nil, errors.New("maxAttempts must be at least 1")
    }
    
    // Use exponential backoff to avoid overwhelming failing services
    backoff := &ExponentialBackoff{
        base: time.Second,
        max:  30 * time.Second,
    }
    
    return &RetryMiddleware{
        attempts: maxAttempts,
        backoff:  backoff,
    }, nil
}

Error Handling

  • Always check errors: if err != nil
  • Use standard library errors package (not github.com/pkg/errors)
  • Wrap errors with context: fmt.Errorf("failed to load config: %w", err)
  • Don’t ignore errors (linter will catch this)

Testing

Test Coverage

  • Write tests for all new functionality
  • Maintain or improve existing coverage
  • Include both positive and negative test cases

Test Organization

func TestCreateRetryMiddleware(t *testing.T) {
    t.Run("valid configuration", func(t *testing.T) {
        mw, err := CreateRetryMiddleware(3)
        require.NoError(t, err)
        assert.NotNil(t, mw)
    })
    
    t.Run("invalid max attempts", func(t *testing.T) {
        _, err := CreateRetryMiddleware(0)
        require.Error(t, err)
    })
}

Running Tests

make test-unit

Dependencies

  • Prefer standard library over external dependencies
  • Dependencies in go.mod must reference tags (not commits)
  • If tag not possible, add a comment explaining why
  • Run make validate to check vendor consistency

Pull Request Guidelines

Before Submitting

Run all validation steps locally:
1

Generate Code

make generate
make generate-crd
2

Validate

make validate
3

Test

make pull-images
make test
Your PR will not be reviewed until all CI checks are green. Running these locally first saves time.

PR Best Practices

Size Matters

Keep PRs Small: Large PRs take longer to review and are more likely to be rejected. Break large changes into multiple smaller PRs when possible.
  • Each PR should solve one problem
  • If you can extract separate concerns, do it
  • Multiple small PRs > one large PR
  • Aim for < 400 lines changed when possible

PR Template

Use the PR template and fill it out completely:
  • Description: What does this PR do?
  • Motivation: Why is this change needed?
  • Related issues: Link to issues (e.g., Fixes #1234)
  • Type of change: Bug fix, feature, docs, etc.
  • Testing: How did you test this?

PR Settings

  • Not from organization: Open PR from your personal fork, not organization repo
  • Allow edits: Keep “Allow edits from maintainers” checked
  • Not a draft: We don’t review drafts (but we answer questions on them)
  • Semantic line breaks: Use in documentation (one sentence per line)

PR Review Process

The review process follows these stages:
1

Triage

We verify prerequisites and assign reviewers.
2

Design Review

We check for conflicts with existing codebase (takes longest).
3

Code Review

In-depth code review with testing. We may request changes.
4

Approval

Requires 2 LGTM (Looks Good To Me) from maintainers.
5

Merge

Bot automatically merges when ready (squash-rebase by default).

Response Time

  • Be reasonably responsive during code review
  • Stale PRs (>90 days without feedback) may be closed
  • Re-request review after addressing feedback
  • Comment to bump visibility during triage

Merge Process

PRs are managed by Myrmica Lobicornis bot:
  • Verifies all checks pass
  • Ensures minimum reviews (2 LGTM)
  • Rebases or merges with base branch if needed
  • Performs squash-rebase merge by default

Labels

  • status/3-needs-merge - Triggers merge bot (added by maintainer)
  • status/4-merge-in-progress - Bot is merging (automatic)
  • bot/need-human-merge - Conflicts or issues require manual intervention
  • bot/no-merge - Prevents automatic merge
  • bot/light-review - Reduces required LGTMs from 2 to 1 (docs, deps, etc.)

Common Issues

Why Was My PR Closed?

PRs may be closed if:
  • Design conflicts: Changes conflict with codebase architecture
    • Prevention: Create an issue first and discuss design
  • Out of scope: Feature won’t be used or doesn’t align with goals
    • Prevention: Get maintainer feedback on an issue first
  • Stale: No contributor feedback for >90 days
    • Prevention: Respond to review comments promptly

Why Isn’t My PR Being Reviewed?

Common reasons:

Priority

We prioritize:
  1. PRs with contributor/wanted tag
  2. Bug fixes (especially bug/confirmed)
  3. Documentation updates
  4. Other PRs

Not Following Best Practices

  • No issue created before PR
  • PR too large (should be broken up)
  • Insufficient comments
  • Missing or inadequate tests
  • Failing CI checks

Release Freeze

During final weeks of milestone, we pause reviews to stabilize for release.

Code Style Examples

Good Examples

// Good: Always check and wrap errors with context
config, err := LoadConfig(path)
if err != nil {
    return fmt.Errorf("failed to load config from %s: %w", path, err)
}

Bad Examples

// Bad: Ignoring errors
config, _ := LoadConfig(path)

// Bad: Not wrapping errors
if err != nil {
    return err
}

It’s OK to Push Back

Reviewers make mistakes too! If you have good reasons for doing something differently:
  • Politely explain your reasoning
  • Provide evidence or references
  • Be open to discussion
  • Stay respectful
You might be overruled, but you might also prevail. We’re reasonable people.

Common Sense and Courtesy

  • Be respectful and professional
  • Be open-minded - consider other perspectives
  • Keep communication public (don’t DM maintainers)
  • Stay away from defensive comments
  • Express yourself clearly (many aren’t native English speakers)
  • Remember: we all want to improve the project

Documentation

When changing functionality:
  • Update relevant documentation
  • Use semantic line breaks (one sentence per line)
  • Include code examples
  • Update configuration references if needed
See the Documentation Guide for building docs locally.

Security

Never commit:
  • Credentials or API keys
  • .env files with secrets
  • Private keys or certificates
For security issues, follow the Security Policy.

Getting Help

Stuck? Need help?
  • Testing: Ask in your PR comments - we’re happy to suggest test cases
  • Design: Create an issue to discuss before coding
  • Review: Re-request review or comment to bump visibility
  • Community: Ask on community.traefik.io

Next Steps

Now you’re ready to contribute!
  1. Find an issue to work on
  2. Create your branch and make changes
  3. Run validation and tests locally
  4. Submit your PR
  5. Respond to review feedback
Thank you for making Traefik better!