Open-Source Wikis

/

Envoy

/

How to contribute

/

Development workflow

envoyproxy/envoy

Development workflow

The end-to-end lifecycle of a change to Envoy.

1. Communicate (for anything > ~100 LOC)

For anything beyond a small bugfix or doc tweak, open or comment on a GitHub issue first. The contributing guide defines a "major feature" as anything > 100 LOC altered (excluding tests) or anything that changes user-facing behavior, and asks for an issue + design discussion before code is written. New extensions in particular have their own gatekeeping process — see EXTENSION_POLICY.md.

2. Branch and code

Fork the repo and branch from main. Use a descriptive branch name; there is no enforced convention. Sign off every commit (git commit -s) for the DCO.

While editing:

  • Match the existing file's style. Read patterns and conventions before writing new code.
  • Keep public interfaces in envoy/ abstract (pure virtual). Implementation goes in source/.
  • If you add a new public interface, add a corresponding mock under test/mocks/.
  • If you add a new extension, register it in source/extensions/extensions_build_config.bzl (or all_extensions.bzl for non-removable ones), add metadata to extensions_metadata.yaml, and add CODEOWNERS entries.

3. Format and lint

Before pushing:

# Repo-wide format check (read-only)
tools/code_format/check_format.py check

# Apply formatting fixes in place
tools/code_format/check_format.py fix

# Faster: only check files changed against main
./tools/local_fix_format.sh

# clang-tidy is checked in CI, run locally if you've changed C++:
./ci/run_clang_tidy.sh

The .clang-format and .clang-tidy files at the repo root encode the canonical rules. The check_format.py checks include the inclusive-language policy, license headers, banned tokens, ordering of #include blocks, namespace usage, smart-pointer aliasing, ordering of BUILD deps, etc. — many things clang-format doesn't see.

4. Build and test

Local iteration loop:

# Compile core
bazel build -c dbg //source/exe:envoy-static

# Run a focused unit test
bazel test //test/common/http:filter_manager_test

# Run an integration test
bazel test //test/integration:integration_test

# Run with a sanitizer
bazel test --config=asan //test/common/http/...

The Testing page goes deeper. The CI configuration mirrors what you can run locally; see ci/ for the canonical scripts.

5. Add a release note (if user-visible)

If the change is user-visible or affects extension developers, add a YAML entry to changelogs/current.yaml. The format is enforced by tools/release_notes/check.py. Entries are alphabetised by subsystem.

Categories:

  • behavior_changes — changes that may break existing users
  • minor_behavior_changes — minor effects, runtime-guarded
  • bug_fixes — bug fixes
  • removed_config_or_runtime — removed deprecated config
  • new_features — new features
  • deprecated — newly deprecated config

6. Add a runtime guard (if behavioural)

Behavioural changes go behind a runtime feature flag so they can be disabled in production by setting the flag in Bootstrap.layered_runtime or via RTDS. Pattern:

constexpr absl::string_view kMyChangeRuntimeFlag =
    "envoy.reloadable_features.my_change_name";

if (Runtime::runtimeFeatureEnabled(kMyChangeRuntimeFlag)) {
  // new behaviour
} else {
  // old behaviour
}

The flag must be registered in source/common/runtime/runtime_features.cc with its default. Most new flags default to true (the new behaviour is on) and exist for emergency rollback. Old flags are removed after a release cycle if no one disables them.

7. Open the PR

Use the PULL_REQUEST_TEMPLATE.md. The fields are explained in PULL_REQUESTS.md:

  • Title. subsystem: brief change description — both lower-case, e.g. router: add x-envoy-overloaded header.
  • Risk level. Low / Medium / High. Bug fixes are usually Low, new filters Medium, flow-control rewrites High.
  • Testing. What you tested. Unit, integration, manual.
  • Documentation. Note any docs changes, especially Life of a Request for data-plane structural changes.
  • Release notes. Reference your changelogs/current.yaml change or write N/A.
  • Runtime guard. Name the flag.
  • API Considerations. If you touched anything under api/, walk through the API review checklist.

8. CI

Azure Pipelines runs the full matrix on every push to your PR. The pipeline is defined in .azure-pipelines/ and orchestrated by scripts under ci/. Significant jobs include:

  • format — runs tools/code_format/check_format.py check and a few other lints.
  • compile_time_options — builds with most options flipped (deprecated features off, FIPS, etc.).
  • gcc, clang, clang_libcxx, sanitizer builds (asan/tsan/msan/ubsan), coverage build, fuzz build.
  • release — produces envoy-static and the contrib equivalent for linux/amd64 and linux/arm64.

You may need to push fixes; CI is mostly stable but flaky integration tests do exist (see the copilot/disable-flaky-... branches in the remote for the kinds of issues that come up).

9. Review

The reviewer team is split into:

  • CODEOWNERS for the directory you touched (see CODEOWNERS). At least one CODEOWNER approval is required.
  • Senior maintainer for security-sensitive or high-risk changes.
  • The reviewers.yaml file feeds the repokitteh bot which auto-assigns reviewers based on the changed paths.

Conventions during review:

  • Reviewers leave comments inline; you address them with git commit --amend or git commit --fixup and force-push, or with new commits that get squashed at merge.
  • The kthxbye slash command (from repokitteh) is used to auto-merge PRs once everything is green and approved.
  • "Bumps PR" — comments asking for a re-review after addressing feedback — are common and expected.

10. Merge

The final commit message is the PR description (the GitHub "squash and merge" model). Maintainers will edit your description if it doesn't match the canonical commit-message format. Once merged, your change lands on main and is built by CI for the next nightly Docker image.

Backporting

If your fix is needed in an existing release line, follow BACKPORTS.md: cherry-pick onto release/v1.X, open a PR against that branch, and tag it with backport. Security backports follow SECURITY.md.

See also

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

Development workflow – Envoy wiki | Factory