diff --git a/README.md b/README.md
index ede2997bb..1f23f98ca 100644
--- a/README.md
+++ b/README.md
@@ -1,98 +1,97 @@
-[](https://sourcegraph.com/github.com/labstack/echo?badge)
-[](https://pkg.go.dev/github.com/labstack/echo/v4)
-[](https://goreportcard.com/report/github.com/labstack/echo)
-[](https://github.com/labstack/echo/actions)
-[](https://codecov.io/gh/labstack/echo)
-[](https://github.com/labstack/echo/discussions)
-[](https://twitter.com/labstack)
-[](https://raw.githubusercontent.com/labstack/echo/master/LICENSE)
+[](https://pkg.go.dev/github.com/labstack/echo/v4)
+[](https://github.com/labstack/echo/actions/workflows/echo.yml?query=branch%3Av4)
+[](https://codecov.io/gh/labstack/echo/tree/v4)
+[](https://github.com/labstack/echo/discussions)
+[](https://x.com/labstack)
+[](https://github.com/labstack/echo/blob/v4/LICENSE)
-## Echo
+## Echo v4
High performance, extensible, minimalist Go web framework.
-* [Official website](https://echo.labstack.com)
-* [Quick start](https://echo.labstack.com/docs/quick-start)
-* [Middlewares](https://echo.labstack.com/docs/category/middleware)
+This branch holds Echo v4, the maintenance line. Echo v5 is the current release; start new projects on [v5](https://github.com/labstack/echo).
-Help and questions: [Github Discussions](https://github.com/labstack/echo/discussions)
+- [v4 API reference](https://pkg.go.dev/github.com/labstack/echo/v4)
+- [Upgrade from v4 to v5](https://github.com/labstack/echo/blob/master/API_CHANGES_V5.md)
+- [Website](https://echo.labstack.com) (documents v5)
+- Community help: [GitHub Discussions](https://github.com/labstack/echo/discussions)
+- Commercial support: [Echo Support](https://echo.labstack.com/pro#support)
+### Support
-### Feature Overview
+Echo v4 receives bug fixes until 2026-12-31 and free security fixes until 2027-12-31, on its latest release only. It gets no new features. See [SECURITY.md](https://github.com/labstack/echo/blob/master/SECURITY.md) for the full policy.
-- Optimized HTTP router which smartly prioritize routes
-- Build robust and scalable RESTful APIs
-- Group APIs
-- Extensible middleware framework
-- Define middleware at root, group or route level
-- Data binding for JSON, XML and form payload
-- Handy functions to send variety of HTTP responses
-- Centralized HTTP error handling
-- Template rendering with any template engine
-- Define your format for the logger
-- Highly customizable
-- Automatic TLS via Let’s Encrypt
-- HTTP/2 support
-
-## Sponsors
+Echo v4 requires Go 1.26 or later (since v4.16.1), to use patched `golang.org/x/` dependencies.
-
-
-
-
-
-Click [here](https://github.com/sponsors/labstack) for more information on sponsorship.
-
-## [Guide](https://echo.labstack.com/guide)
+[Echo Support](https://echo.labstack.com/pro#support) is a paid annual plan from LabStack for v4 and v5 applications. It includes a named contact, email support with a two-business-day response target, and an annual maintenance-status letter.
-### Installation
-
-```sh
-// go get github.com/labstack/echo/{version}
-go get github.com/labstack/echo/v4
-```
-Echo v4.16.1 and later require Go 1.26 or later to use patched `golang.org/x/` dependencies. Use a supported, patched Go toolchain when building applications.
-
-Echo v4 receives bug fixes until 2026-12-31 and free security fixes until 2027-12-31, on its latest release. New projects should use [v5](https://github.com/labstack/echo). See [SECURITY.md](https://github.com/labstack/echo/blob/master/SECURITY.md) for the full policy.
+## Upgrade notes
### Client IP security migration since v4.16.3
-Echo v4.16.3 changes client IP defaults: without `Echo#IPExtractor`, `Context.RealIP()` uses the connection peer and ignores `X-Forwarded-For` and `X-Real-IP`. Proxy middleware always replaces upstream `X-Real-IP` with this result. This fixes CVE-2026-118651 and CVE-2026-118653.
+Echo v4.16.3 changes client IP defaults. Without `Echo#IPExtractor`, `Context.RealIP()` uses the connection peer and ignores `X-Forwarded-For` and `X-Real-IP`. Proxy middleware always replaces upstream `X-Real-IP` with this result. This fixes [CVE-2026-118651](https://github.com/labstack/echo/security/advisories/GHSA-99jh-6h7p-pp36) and [CVE-2026-118653](https://github.com/labstack/echo/security/advisories/GHSA-246p-cpwv-v3jq). Applications that already set `Echo#IPExtractor` keep their behavior. A custom rate-limit identifier that does not call `RealIP()` is also unaffected.
-**Migration for applications behind proxies:** configure `Echo#IPExtractor` before starting the server. Otherwise, clients behind the same proxy share its IP address for rate limiting, access controls, and logging. Use `echo.ExtractIPDirect()` when there is no proxy. For XFF-based proxies, disable the broad default trust ranges and trust only your proxy addresses:
+Behind a proxy, configure `Echo#IPExtractor` before starting the server. Otherwise, clients behind the same proxy share its IP address for rate limiting, access controls and logging. Use `echo.ExtractIPDirect()` when there is no proxy. For proxies that set `X-Forwarded-For`, turn off the broad default trust ranges and trust only your proxy addresses:
```go
+// After e := echo.New(); imports "log" and "net".
_, proxyRange, err := net.ParseCIDR("10.0.0.10/32") // replace with your proxy's address or CIDR
if err != nil {
- log.Fatal(err)
+ log.Fatal(err)
}
e.IPExtractor = echo.ExtractIPFromXFFHeader(
- echo.TrustLoopback(false),
- echo.TrustLinkLocal(false),
- echo.TrustPrivateNet(false),
- echo.TrustIPRange(proxyRange),
+ echo.TrustLoopback(false),
+ echo.TrustLinkLocal(false),
+ echo.TrustPrivateNet(false),
+ echo.TrustIPRange(proxyRange),
)
```
-If your proxy uses `X-Real-IP`, use `echo.ExtractIPFromRealIPHeader` with the same trust options. Configure the outermost proxy to replace client-supplied identity headers. Explicitly configured extractors and custom rate-limit identifiers retain their behavior.
+If your proxy uses `X-Real-IP`, use `echo.ExtractIPFromRealIPHeader` with the same trust options. Configure the outermost proxy to replace client-supplied identity headers.
### Security defaults since v4.16.1
-`BodyDump` captures at most 5 MiB of the request and 5 MiB of the response by default. The application and client still receive the complete bodies. Configure `BodyDumpConfig.MaxRequestBytes` and `MaxResponseBytes` to change the capture limits; `-1` disables a limit.
+See the [v4.16.1 release notes](https://github.com/labstack/echo/releases/tag/v4.16.1) for the advisories.
+
+`BodyDump` captures at most 5 MiB of the request and 5 MiB of the response by default. The application and client still receive the complete bodies. Set `BodyDumpConfig.MaxRequestBytes` and `MaxResponseBytes` to change the capture limits; `-1` removes a limit.
+
+`Decompress` limits decompressed request bodies to 100 MiB by default. Reading beyond the limit returns HTTP 413, including through JSON and XML binding. Set `DecompressConfig.MaxDecompressedSize` to change the limit; `-1` removes it. Apply any smaller application body limit after decompression.
+
+The proxy middleware validates WebSocket upgrade responses, closes both WebSocket connections when either side disconnects, and removes incoming `Forwarded` headers. Backends should trust only the forwarding headers the proxy sets and enforce their own authorization.
+
+### Request scheme since v4.16.0
+
+`Context.Scheme()` uses `X-Forwarded-Proto` and related headers only when the request comes directly from a loopback, link-local or private network address, or a unix socket. If a proxy with a public address terminates TLS and forwards plain HTTP to Echo, `HTTPSRedirect` keeps redirecting until you set `Echo#SchemeExtractor` to trust that proxy. See the [v4.16.0 changelog](https://github.com/labstack/echo/blob/v4/CHANGELOG.md#v4160---2026-09-27) for this and the other fixes in that release.
-`Decompress` limits decompressed request bodies to 100 MiB by default. Reading beyond the limit returns HTTP 413, including through JSON and XML binding. Configure `DecompressConfig.MaxDecompressedSize` to change the limit; `-1` disables it. Apply any smaller application body limit after decompression.
+## Features
-The proxy now validates WebSocket upgrade responses, closes both WebSocket connections when either side disconnects, and removes incoming `Forwarded` headers. Backends should use the proxy's validated forwarding headers and enforce their own authorization.
+- Router with static, parameter and wildcard routes; static routes match first
+- RESTful APIs with route groups
+- Middleware at the root, group or route level
+- Data binding for JSON, XML, form, query and path parameters
+- Helpers for common HTTP responses
+- Centralized HTTP error handling
+- Template rendering with any template engine
+- Customizable logging
+- Automatic TLS through Let's Encrypt
+- HTTP/2, including h2c
+
+## Sponsors
+
+| | Sponsor |
+| --- | --- |
+|
| [Blacksmith](https://blacksmith.sh): faster, drop-in GitHub Actions runners |
+|
| [Encore](https://encore.dev): the platform for building Go-based cloud backends |
+
+Echo is independent and community funded. If your company depends on Echo, please consider [sponsoring it](https://github.com/sponsors/labstack).
+
+## Getting started
+
+### Installation
+
+```sh
+go get github.com/labstack/echo/v4
+```
### Example
@@ -100,87 +99,77 @@ The proxy now validates WebSocket upgrade responses, closes both WebSocket conne
package main
import (
- "github.com/labstack/echo/v4"
- "github.com/labstack/echo/v4/middleware"
- "log/slog"
- "net/http"
+ "errors"
+ "log/slog"
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+ "github.com/labstack/echo/v4/middleware"
)
func main() {
- // Echo instance
- e := echo.New()
+ e := echo.New()
- // Middleware
- e.Use(middleware.RequestLogger()) // use the default RequestLogger middleware with slog logger
- e.Use(middleware.Recover()) // recover panics as errors for proper error handling
+ e.Use(middleware.RequestLogger()) // log requests with slog
+ e.Use(middleware.Recover()) // turn panics into errors
- // Routes
- e.GET("/", hello)
+ e.GET("/", hello)
- // Start server
- if err := e.Start(":8080"); err != nil && !errors.Is(err, http.ErrServerClosed) {
- slog.Error("failed to start server", "error", err)
- }
+ if err := e.Start(":8080"); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ slog.Error("failed to start server", "error", err)
+ }
}
-// Handler
func hello(c echo.Context) error {
- return c.String(http.StatusOK, "Hello, World!")
+ return c.String(http.StatusOK, "Hello, World!")
}
```
-# Official middleware repositories
+## Official middleware
-Following list of middleware is maintained by Echo team.
+The Echo team maintains these repositories.
-| Repository | Description |
-|------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| [github.com/labstack/echo-jwt](https://github.com/labstack/echo-jwt) | [JWT](https://github.com/golang-jwt/jwt) middleware |
-| [github.com/labstack/echo-contrib](https://github.com/labstack/echo-contrib) | [casbin](https://github.com/casbin/casbin), [gorilla/sessions](https://github.com/gorilla/sessions), [jaegertracing](https://github.com/uber/jaeger-client-go), [prometheus](https://github.com/prometheus/client_golang/), [pprof](https://pkg.go.dev/net/http/pprof), [zipkin](https://github.com/openzipkin/zipkin-go) middlewares |
-| [github.com/labstack/echo-otel](https://github.com/labstack/echo-otel/tree/v4) | [OpenTelemetry](https://opentelemetry.io/) middleware for tracing and metrics (`github.com/labstack/echo-otel/v4`) |
+| Repository | Description |
+| --- | --- |
+| [github.com/labstack/echo-jwt](https://github.com/labstack/echo-jwt) | [JWT](https://github.com/golang-jwt/jwt) middleware |
+| [github.com/labstack/echo-contrib](https://github.com/labstack/echo-contrib) | [casbin](https://github.com/casbin/casbin), [gorilla/sessions](https://github.com/gorilla/sessions), [jaegertracing](https://github.com/uber/jaeger-client-go), [prometheus](https://github.com/prometheus/client_golang/), [pprof](https://pkg.go.dev/net/http/pprof) and [zipkin](https://github.com/openzipkin/zipkin-go) middleware |
+| [github.com/labstack/echo-otel](https://github.com/labstack/echo-otel/tree/v4) | [OpenTelemetry](https://opentelemetry.io/) tracing and metrics middleware (`github.com/labstack/echo-otel/v4`) |
-# Third-party middleware repositories
+## Third-party middleware
-Be careful when adding 3rd party middleware. Echo teams does not have time or manpower to guarantee safety and quality
-of middlewares in this list.
+The Echo team does not review or maintain these projects. Check their quality and security, and that each one supports v4, before you use them.
-| Repository | Description |
-|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| [deepmap/oapi-codegen](https://github.com/deepmap/oapi-codegen) | Automatically generate RESTful API documentation with [OpenAPI](https://swagger.io/specification/) Client and Server Code Generator |
-| [github.com/swaggo/echo-swagger](https://github.com/swaggo/echo-swagger) | Automatically generate RESTful API documentation with [Swagger](https://swagger.io/) 2.0. |
-| [github.com/ziflex/lecho](https://github.com/ziflex/lecho) | [Zerolog](https://github.com/rs/zerolog) logging library wrapper for Echo logger interface. |
-| [github.com/brpaz/echozap](https://github.com/brpaz/echozap) | Uber´s [Zap](https://github.com/uber-go/zap) logging library wrapper for Echo logger interface. |
-| [github.com/samber/slog-echo](https://github.com/samber/slog-echo) | Go [slog](https://pkg.go.dev/golang.org/x/exp/slog) logging library wrapper for Echo logger interface. |
-| [github.com/darkweak/souin/plugins/echo](https://github.com/darkweak/souin/tree/master/plugins/echo) | HTTP cache system based on [Souin](https://github.com/darkweak/souin) to automatically get your endpoints cached. It supports some distributed and non-distributed storage systems depending your needs. |
-| [github.com/mikestefanello/pagoda](https://github.com/mikestefanello/pagoda) | Rapid, easy full-stack web development starter kit built with Echo. |
-| [github.com/go-woo/protoc-gen-echo](https://github.com/go-woo/protoc-gen-echo) | ProtoBuf generate Echo server side code |
+| Repository | Description |
+| --- | --- |
+| [oapi-codegen/oapi-codegen](https://github.com/oapi-codegen/oapi-codegen) | Generates server and client code from [OpenAPI](https://swagger.io/specification/) specifications |
+| [github.com/swaggo/echo-swagger](https://github.com/swaggo/echo-swagger) | Serves [Swagger](https://swagger.io/) 2.0 API documentation |
+| [github.com/ziflex/lecho](https://github.com/ziflex/lecho) | [Zerolog](https://github.com/rs/zerolog) adapter for the Echo logger interface |
+| [github.com/brpaz/echozap](https://github.com/brpaz/echozap) | Uber's [Zap](https://github.com/uber-go/zap) adapter for the Echo logger interface |
+| [github.com/samber/slog-echo](https://github.com/samber/slog-echo) | [slog](https://pkg.go.dev/log/slog) request logging middleware |
+| [github.com/darkweak/souin/plugins/echo](https://github.com/darkweak/souin/tree/master/plugins/echo) | HTTP cache based on [Souin](https://github.com/darkweak/souin), with distributed and local storage backends |
+| [github.com/mikestefanello/pagoda](https://github.com/mikestefanello/pagoda) | Full-stack web starter kit built with Echo |
+| [github.com/go-woo/protoc-gen-echo](https://github.com/go-woo/protoc-gen-echo) | Generates Echo server code from Protocol Buffers |
-Please send a PR to add your own library here.
+To add your library, send a pull request.
## Contribute
-**Use issues for everything**
+v4 takes bug and security fixes only (see [Support](#support)). Send new features to v5 on the [master branch](https://github.com/labstack/echo).
+
+- Open an issue before a large change. Send small fixes directly as a pull request.
+- Include a test, documentation and, where it helps, an example.
-- For a small change, just send a PR.
-- For bigger changes open an issue for discussion before sending a PR.
-- PR should have:
- - Test case
- - Documentation
- - Example (If it makes sense)
-- You can also contribute by:
- - Reporting issues
- - Suggesting new features or enhancements
- - Improve/fix documentation
+Report security issues privately as [SECURITY.md](https://github.com/labstack/echo/blob/master/SECURITY.md) describes, not in public issues.
## Credits
-- [Vishal Rana](https://github.com/vishr) (Author)
+- [Vishal Rana](https://github.com/vishr) (Author and Maintainer)
- [Nitin Rana](https://github.com/nr17) (Consultant)
-- [Roland Lammel](https://github.com/lammel) (Maintainer)
-- [Martti T.](https://github.com/aldas) (Maintainer)
-- [Pablo Andres Fuente](https://github.com/pafuent) (Maintainer)
+- [Martti T.](https://github.com/aldas) (Maintainer Emeritus)
+- [Roland Lammel](https://github.com/lammel) (Maintainer Emeritus)
+- [Pablo Andres Fuente](https://github.com/pafuent) (Maintainer Emeritus)
- [Contributors](https://github.com/labstack/echo/graphs/contributors)
## License
-[MIT](https://github.com/labstack/echo/blob/master/LICENSE)
+[MIT](https://github.com/labstack/echo/blob/v4/LICENSE)