⚠️ Breaking Changes
- chore(digitalocean)!: remove in-tree provider by @simonoff in #6283
- chore(source)!: remove cloudfoundry support by @ivankatliarchuk in #6074
- feat!: generalize PTR record support from rfc2136 to all providers by @clwluvw in #6232
- feat(pihole)!: deprecate v5 API support by @ivankatliarchuk in #6123
- feat(service)!: ignore unschedulable nodes by @ivankatliarchuk in #6002
- feat(source/gateway-api)!: migrate Gateway and HTTPRoute to v1 by @System-Arch in #6291
- feat(source/istio)!: migrate gateway and virtualservice sources to networking.istio.io/v1 by @ivankatliarchuk in #6302
🚀 Features
- feat(aws): enable support for NAPTR records by @alexbakker-quandago in #6022
- feat(azure): dns metadata (tags) support by @vaspoz in #5984
- feat(client): add --kube-api-qps and --kube-api-burst flags for Kubernetes client rate limiting by @ivankatliarchuk in #6322
- feat(cli): remove cobra cli support by @ivankatliarchuk in #6034
- feat(cloudflare): support batch API for DNS record changes by @mooseracerPT in #6208
- feat(coredns): rename ownerId and ownedBy to owner by @farodin91 in #6032
- feat(coredns): use txt-owner-id to strictly separated external-dns instances by @farodin91 in #5921
- feat(crd): Support MX record with trailing dot by @HartmannVolker in #6163
- feat(endpoint): introduce record-type annotation and PTR endpoint helpers by @clwluvw in #6282
- feat(endpoint): reject alias property on unsupported record types by @u-kai in #6188
- feat(endpoint): validate PTR records in CheckEndpoint by @clwluvw in #6275
- feat: end to end testing with coredns provider by @Raffo in #5933
- feat(event): emit events for ingress,svc,pod,node,crd by @ivankatliarchuk in #6099
- feat(event): standardize event messages and add resource kind lookup for events by @ivankatliarchuk in #6101
- feat(fqdn): Deduplicate and sort ExecTemplate output. Add functions by @ivankatliarchuk in #6173
- feat(gateway): add gateway-api listenerset support by @jukie in #6254
- feat(informers): reduce informer cache memory footprint via object transformers by @ivankatliarchuk in #6240
- feat(metrics): added skipped_records_owner_mismatch_per_sync to track ownership conflicts by @ivankatliarchuk in #6121
- feat(pdns): add --[no-]prefer-alias flag and alias annotation support by @ngnix in #6129
- feat(pdns): support GetDomainFilter interface by @clwluvw in #6234
- feat(pihole)!: deprecate v5 API support by @ivankatliarchuk in #6123
- feat(registry/txt): enable support for SRV and NAPTR by @alexbakker-quandago in #6023
- feat(service)!: ignore unschedulable nodes by @ivankatliarchuk in #6002
- feat(source): add support for ingress backed GlooEdge Gateway by @cucxabong in #5909
- feat(source): add unstructured source by @ivankatliarchuk in #6172
- feat(source): gateway api hostname source annotation by @bogdankrasko in #5959
- feat(source/gateway-api)!: migrate Gateway and HTTPRoute to v1 by @System-Arch in #6291
- feat(source/istio)!: migrate gateway and virtualservice sources to networking.istio.io/v1 by @ivankatliarchuk in #6302
- feat(txt): add PTR record support to TXT registry mapper and PowerDNS trailing-dot handling by @clwluvw in #6281
- feat(webhook): instrument HTTP client with request duration metrics by @ivankatliarchuk in #6307
🐛 Bug fixes
- fix(annotations): initialize annotation keys at declaration time by @ivankatliarchuk in #6159
- fix(api): rollback changes for omitempty by @ivankatliarchuk in #6086
- fix(aws): use API validation for routing policies by @u-kai in #6082
- fix(chart): ptsc indentation by @andylim0221 in #6054
- fix(charts): add schema for provider.webhook.serviceMonitor by @chrisbsmith in #5932
- fix(charts): Skip cluster-scope RBAC on namespaced by @TobyTheHutt in #5843
- fix(ci): failed to download the coveralls binary from GitHub releases by @ivankatliarchuk in #6228
- fix(cloudflare): dns records pagination by @rkferreira in #5986
- fix(crd): allow trailing dot in CNAME targets by @ivankatliarchuk in #6218
- fix(domain-exclusion): domain exclusion filter fix by @ivankatliarchuk in #6050
- fix: e2e test with kind by @Raffo in #6162
- fix(endpoint): correct function name in comment by @u-kai in #6122
- fix(endpoint): ensure trailing dot to target as required by RFC 2782 by @frittentheke in #5534
- fix(events): re-enqueue failed events in controller work queue by @lexfrei in #6285
- fix(fake): Fake clientset hangs for 10s per informer with client-go 0.35+ by @ivankatliarchuk in #6235
- fix(flags): restore
--min-ttloption by @vflaux in #6014 - fix(fqdn): remove invalid output by @ivankatliarchuk in #6046
- fix(fqdn): support kind and api version by @ivankatliarchuk in #6097
- fix(lint): remove govet exclusion from tests by @vflaux in #6315
- fix(lint): single file was not modernized by @ivankatliarchuk in #6059
- fix(metrics): add CNAME to known record types by @marie-j in #6115
- fix(pdns): ensure trailing dot for NS records by @blsho in #5992
- fix(rfc2136): wrap DNS resolution errors with SoftError to prevent crashes by @e9169 in #6227
- fix(scripts): helm plugins install disable verify by @vflaux in #6057
- fix(service): classify nodes by best pod state in externalTrafficPolicy=Local by @ivankatliarchuk in #6271
- fix(source): filter provider-specific properties to configured provider by @ivankatliarchuk in #6220
- fix(tlsutils): fix nil error wrapping and wrong env var in TLS config by @ivankatliarchuk in #6198
- fix(webhook): connection pool leaks, stuck goroutines on server hang, and retry correctness by @ivankatliarchuk in #6279
- fix(webhook): increase test client timeouts to prevent flaky tests by @ivankatliarchuk in #6310
- fix(zonefinder): transform zone name to unicode as well by @rbeuque74 in #5980
📝 Documentation
- fix(docs): Fixing typos in docs and comments by @thetillhoff in #5995
- fix(docs): flags by @ivankatliarchuk in #6288
- docs: add anexia docs page by @davidkroell in #6252
- docs: add BIND9 on Kubernetes with Kind tutorial for rfc2136 provider by @clwluvw in #6295
- docs: add bug report guide and improve issue template by @ivankatliarchuk in #6272
- docs: added DeepWiki by @ivankatliarchuk in #6215
- docs: add external-dns-pscloud-webhook to New providers list by @supervillain3000 in #6214
- docs: add infomaniak provider reference by @M0NsTeRRR in #6258
- docs: add instructions for local testing by @mloiseleur in #5887
- docs: add operational best practices guide by @ivankatliarchuk in #6287
- docs: add UniFi webhook provider to README by @lexfrei in #5967
- docs(aws): tutorial with kind and localstack by @ivankatliarchuk in #6048
- docs: Consistency review on namespaced configs in chart readme by @josemaia in #6146
- docs(contributor): GetDomainFilter contract and ZoneCache blueprint for provider contributors by @ivankatliarchuk in #6249
- docs: correct pod internal-hostname behavior in hostNetwork mode by @cxmcc in #6256
- docs: fix nested list indentation for web rendering by @ROunofF in #6092
- docs: fix typo in README by @hritz220 in #6095
- docs(fqdn-template): clarify fields and add examples by @ivankatliarchuk in #6098
- docs(fqdn): use correct arguments order in FQDN Templating custom functions by @zcahana in #6144
- docs(metrics): add Labels column to metrics documentation table by @ivankatliarchuk in #6306
- docs(ownerid): provide more details on migration by @ivankatliarchuk in #5999
- docs(proposal): Gateway API annotation placement clarity proposal by @lexfrei in #5919
- docs(readme): replace incorrect breaking change version v0.20.0 -> v0.19.0 by @mangkoran in #6100
- docs(regexfilter): pitfalls in domain-filter zone partitioning by @ivankatliarchuk in #6255
- docs: remove IBM Cloud DNS from README by @prb112 in #6007
- docs: remove link to external-dns-routeros-provider by @benfiola in #5996
- docs(rfc2136): hard learned lesson about AXFR by @avanier in #6083
- docs(source): autogenerate docs for events by @ivankatliarchuk in #6119
- docs(source): autogenerate docs for sources with go-doc like style by @ivankatliarchuk in #6075
- docs(sources): surface provider-specific annotations support in documentation by @ivankatliarchuk in #6231
📦 Others
- benchmark(endpoint): endpoint benchmarks by @ivankatliarchuk in #6156
- chore: add Simply webhook provider to README by @uozalp in #5979
- chore(aws): document and test behavior for ALB and NLB by @ivankatliarchuk in #6063
- chore(chart): release for v0.20.0 by @vflaux in #6005
- chore: cloudbild instance type bump by @ivankatliarchuk in #6340
- chore(cloudflare): improve tests by @vflaux in #6150
- chore(cloudflare): migrate customhostname to v5 by @AndrewCharlesHay in #5891
- chore(cloudflare): move custom hostnames logic to dedicated files by @vflaux in #6114
- chore(deps): bump github.com/aws/smithy-go from 1.23.2 to 1.24.0 in the dev-dependencies group by @app/dependabot in #5987
- chore(deps): bump github.com/cloudflare/cloudflare-go from v5 to v6 by @vflaux in #6324
- chore(deps): bump github.com/digitalocean/godo from 1.168.0 to 1.169.0 in the dev-dependencies group by @app/dependabot in #5956
- chore(deps): bump github.com/goccy/go-yaml from 1.18.0 to 1.19.0 in the dev-dependencies group by @app/dependabot in #5985
- chore(deps): bump golang.org/x/crypto from 0.44.0 to 0.45.0 by @app/dependabot in #5969
- chore(deps): bump go-linter version by @ivankatliarchuk in #6036
- chore(deps): bump google.golang.org/grpc from 1.79.2 to 1.79.3 by @app/dependabot in #6296
- chore(deps): bump mkdocs by @ivankatliarchuk in #6058
- chore(deps): bump mkdocs-git-revision-date-localized-plugin from 1.5.0 to 1.5.1 in /docs/scripts in the mkdocs-deps group by @app/dependabot in #6161
- chore(deps): bump mkdocs-material from 9.7.1 to 9.7.3 in /docs/scripts in the mkdocs-deps group by @app/dependabot in #6237
- chore(deps): bump pre-commit and fix markdown docs by @ivankatliarchuk in #6241
- chore(deps): bump renovatebot/github-action from 44.0.1 to 44.0.2 in the dev-dependencies group by @app/dependabot in #5950
- chore(deps): bump renovatebot/github-action from 44.0.5 to 44.1.0 in the dev-dependencies group by @app/dependabot in #6027
- chore(deps): bump renovatebot/github-action from 44.1.0 to 44.2.0 in the dev-dependencies group by @app/dependabot in #6029
- chore(deps): bump renovatebot/github-action from 44.2.0 to 44.2.1 in the dev-dependencies group by @app/dependabot in #6051
- chore(deps): bump renovatebot/github-action from 44.2.1 to 44.2.2 in the dev-dependencies group by @app/dependabot in #6064
- chore(deps): bump renovatebot/github-action from 44.2.2 to 44.2.3 in the dev-dependencies group by @app/dependabot in #6080
- chore(deps): bump renovatebot/github-action from 46.1.2 to 46.1.3 in the dev-dependencies group by @app/dependabot in #6243
- chore(deps): bump the dev-dependencies group across 1 directory with 10 updates by @app/dependabot in #5970
- chore(deps): bump the dev-dependencies group across 1 directory with 2 updates by @app/dependabot in #6116
- chore(deps): bump the dev-dependencies group across 1 directory with 39 updates by @app/dependabot in #6259
- chore(deps): bump the dev-dependencies group across 1 directory with 3 updates by @app/dependabot in #6226
- chore(deps): bump the dev-dependencies group across 1 directory with 4 updates by @app/dependabot in #5994
- chore(deps): bump the dev-dependencies group across 1 directory with 4 updates by @app/dependabot in #6018
- chore(deps): bump the dev-dependencies group across 1 directory with 9 updates by @app/dependabot in #5976
- chore(deps): bump the dev-dependencies group with 10 updates by @app/dependabot in #5990
- chore(deps): bump the dev-dependencies group with 10 updates by @app/dependabot in #6010
- chore(deps): bump the dev-dependencies group with 12 updates by @app/dependabot in #6001
- chore(deps): bump the dev-dependencies group with 13 updates by @app/dependabot in #6311
- chore(deps): bump the dev-dependencies group with 2 updates by @app/dependabot in #5962
- chore(deps): bump the dev-dependencies group with 5 updates by @app/dependabot in #6298
- chore(deps): bump the dev-dependencies group with 5 updates by @app/dependabot in #6330
- chore(deps): bump the dev-dependencies group with 7 updates by @app/dependabot in #6267
- chore(deps): bump the dev-dependencies group with 9 updates by @app/dependabot in #6274
- chore(deps): bump the dev-dependencies group with 9 updates by @app/dependabot in #6343
- chore(deps): bump the mkdocs-deps group in /docs/scripts with 2 updates by @app/dependabot in #6273
- chore(deps): bump the mkdocs-deps group in /docs/scripts with 3 updates by @app/dependabot in #6331
- chore(deps): bump the mkdocs-deps group in /docs/scripts with 4 updates by @app/dependabot in #6071
- chore(deps): configure dependabot for mkdocs deps by @ivankatliarchuk in #6067
- chore(deps): tools bump and process in contributor docs by @ivankatliarchuk in #6118
- chore(doc): Adding EKS Pod Identity Associations section for AWS by @sw360cab in #6084
- chore(e2e): remove call to get latest kubectl by @Raffo in #6148
- chore(endpoint): added empty checks by @ivankatliarchuk in #6157
- chore(endpoint): harden AES-GCM encryption and remove sensitive data from logs by @ivankatliarchuk in #6197
- chore(go): upgrade to go1.26 by @vflaux in #6314
- chore(ingress): added tests to cover specific behaviour by @ivankatliarchuk in #6060
- chore(ingress): clarify that both IP and Hostname are collected from LoadBalancer status by @ivankatliarchuk in #6138
- chore(lint): configure modernize linter by @ivankatliarchuk in #6035
- chore(linter): enable unparam by @ivankatliarchuk in #6160
- chore(linter): unused params and functions linter by @ivankatliarchuk in #6142
- chore(lint): update golanci-lint by @vflaux in #6320
- (chore) Minimize GitHub Actions workflow permissions by @Raffo in #6319
- chore: modernize code by @vflaux in #6313
- chore(node): remove warning msg by @ivankatliarchuk in #6070
- chore(provider): zone cache provider interface by @ivankatliarchuk in #6120
- chore(registry): move registries to packages by @ivankatliarchuk in #6066
- chore(release): updates kustomize & docs with v0.20.0 by @mloiseleur in #5958
- chore(set-identifier): expand annotation docs and add test coverage by @ivankatliarchuk in #6230
- chore(source): standardize source fields with sources.Config by @ivankatliarchuk in #6073
- chore(source): standardize sources by @ivankatliarchuk in #6089
- chore(source): standardize sources with merge endpionts and deduplication by @ivankatliarchuk in #6174
- chore(store): Added RESTConfig() to ClientGenerator by @ivankatliarchuk in #6177
- chore(tests): Add YAML-driven integration test framework for sources by @ivankatliarchuk in #6158
- chore(tools): CRD generation script moved and add validation workflow by @ivankatliarchuk in #6079
- chore: update to go 1.25.5 for CVE-2025-61729 and CVE-2025-61727 by @goat-ssh in #6000
- chore(wrapper): centralized endpoint validation by @ivankatliarchuk in #6041
- ci: finish gha pinning by @mloiseleur in #6327
- ci: fix revision label by @ivankatliarchuk in #6332
- ci: read golangci-lint version from scripts/install-tools.sh in lint workflow by @ivankatliarchuk in #6347
- ci: validate Go version consistency across cloudbuild.yaml, go.mod, and go.tool.mod by @ivankatliarchuk in #6323
- deps(dependabot): change frequency by @ivankatliarchuk in #6268
- deps(go): bump go from 1.25.5 -> 1.25.7. CVE fixes by @ivankatliarchuk in #6175
- deps(go): bump go from 1.25.7 -> 1.25.8 by @aibaars in #6305
- linter(goimports): Mixed import groups (internal before external) by @ivankatliarchuk in #6238
- linter(usetesting): enable usetesting by @ivankatliarchuk in #6266
- perf(controller): optimize metrics counting by @ivankatliarchuk in #6124
- perf(source/istio): replace API calls with indexed informer cache for gateway and virtualservice sources by @ivankatliarchuk in #6303
- Pin all GitHub Actions to commit SHAs per Kubernetes policy by @Raffo in #6316
- refactor(annotation): rationalize filtering by @ivankatliarchuk in #6065
- refactor(api): deduplicate addKnownTypes by @ivankatliarchuk in #6087
- refactor(aws): abstract provider-specific boolean parsing by @u-kai in #6078
- refactor(aws): extract and restructure alias-handling logic to enable safe upcoming fixes by @u-kai in #6021
- refactor(controller): controller no longer responsible for SingletonClientGenerator creation by @ivankatliarchuk in #6077
- refactor(controller): reduce coupling for registry and controller by @ivankatliarchuk in #6047
- refactor(docs): documentation generators by @ivankatliarchuk in #6221
- refactor(domainfilter): introduce functional options pattern by @ivankatliarchuk in #6055
- refactore(source): move EndpointsForHostname to endpoints package by @ivankatliarchuk in #6248
- refactor(fqdn): encapsulate FQDN template logic into TemplateEngine by @ivankatliarchuk in #6292
- refactor(informers): unify cache sync functions using generics by @ivankatliarchuk in #6102
- refactor(kubeclient): consolidate duplicate code by @ivankatliarchuk in #6076
- refactor(lint): replace with NewSoftErrorf when possible by @vflaux in #6061
- refactor(plan): cleanup and modernize plan package by @ivankatliarchuk in #6294
- refactor(plan): extract normalizeDNSName to idna package for reuse by @u-kai in #6043
- refactor(plan): reduce Calculate() cyclomatic complexity by @vflaux in #5961
- refactor(provider): introduce factory with uniform New constructor by @ivankatliarchuk in #6276
- refactor(registry): introduce factory with uniform New constructors by @ivankatliarchuk in #6277
- refactor(source/crd): migrate CRD source to controller-runtime cache by @ivankatliarchuk in #6312
- refactor(source): handle context in similar way by @ivankatliarchuk in #6049
- refactor(source): inline label selector matching, remove MatchesServiceSelector by @ivankatliarchuk in #6304
- refactor(source): move SuitableType to endpoint package by @ivankatliarchuk in #6239
- refactor(source): standardize FQDN template accross sources by @ivankatliarchuk in #6093
- refactor(source): use less memory on deduplication by @mloiseleur in #6020
- refactor(test): deduplicate endpoint assertion helpers across source by @ivankatliarchuk in #6299
- refactor(testutils): extract log test helpers into subpackage to fix circular import by @u-kai in #6236
- refactor(wrappers): introduce wrapper.Build as single entry point for source pipeline by @ivankatliarchuk in #6300
- Revert "chore(deps): bump github.com/cloudflare/cloudflare-go from v5 to v6" by @ivankatliarchuk in #6338
- test: cover pkg/events/fake package by @hritz220 in #6096
- test: fix typos in code & comment by @dongjiang1989 in #6011
- test(fqdn): cover sources without any fqdn tests by @ivankatliarchuk in #6094
- test: improve code coverage by @ivankatliarchuk in #6321
- test: improve code coverage on aws, cloudfoundry & nat64 source by @ivankatliarchuk in #6045
- test(provider): improved the test coverage for exoscale provider by @upsaurav12 in #6112
📦 Docker Image
# This pull command only works when it's released
docker pull registry.k8s.io/external-dns/external-dns:v0.21.0