1
0
mirror of https://github.com/labstack/echo.git synced 2026-03-12 15:46:17 +02:00
Files
echo/API_CHANGES_V5.md

29 KiB

Echo v5 Public API Changes

Comparison between master (v4.15.0) and v5 (v5.0.0-alpha) branches

Generated: 2026-01-01


Executive Summary (by authors)

Echo v5 is maintenance release with major breaking changes

  • Context is now struct instead of interface and we can add method to it in the future in minor versions.
  • Adds new Router interface for possible new routing implementations.
  • Drops old logging interface and uses moderm log/slog instead.
  • Rearranges alot of methods/function signatures to make them more consistent.

Executive Summary (by LLMs)

Echo v5 represents a major breaking release with significant architectural changes focused on:

  • Updated generic helpers to take *Context and rename form helpers to FormValue*
  • Simplified API surface by moving Context from interface to concrete struct
  • Modern Go patterns including slog.Logger integration
  • Enhanced routing with explicit RouteInfo and Routes types
  • Better error handling with simplified HTTPError
  • New test helpers via the echotest package

Change Statistics

  • Major Breaking Changes: 15+
  • New Functions Added: 30+
  • Type Signature Changes: 20+
  • Removed APIs: 10+
  • New Packages Added: 1 (echotest)
  • Version Change: 4.15.05.0.0-alpha

Critical Breaking Changes

1. Context: Interface → Concrete Struct

v4 (master):

type Context interface {
    Request() *http.Request
    // ... many methods
}

// Handler signature
func handler(c echo.Context) error

v5:

type Context struct {
    // Has unexported fields
}

// Handler signature - NOW USES POINTER!
func handler(c *echo.Context) error

Impact: 🔴 CRITICAL BREAKING CHANGE

  • ALL handlers must change from echo.Context to *echo.Context
  • Context is now a concrete struct, not an interface
  • This affects every single handler function in user code

Migration:

// Before (v4)
func MyHandler(c echo.Context) error {
    return c.JSON(200, map[string]string{"hello": "world"})
}

// After (v5)
func MyHandler(c *echo.Context) error {
    return c.JSON(200, map[string]string{"hello": "world"})
}

2. Logger: Custom Interface → slog.Logger

v4:

type Echo struct {
    Logger Logger  // Custom interface with Print, Debug, Info, etc.
}

type Logger interface {
    Output() io.Writer
    SetOutput(w io.Writer)
    Prefix() string
    // ... many custom methods
}

// Context returns Logger interface
func (c Context) Logger() Logger

v5:

type Echo struct {
    Logger *slog.Logger  // Standard library structured logger
}

// Context returns slog.Logger
func (c *Context) Logger() *slog.Logger
func (c *Context) SetLogger(logger *slog.Logger)

Impact: 🔴 BREAKING CHANGE

  • Must use Go's standard log/slog package
  • Logger interface completely removed
  • All logging code needs updating

3. Router: From Router to DefaultRouter

v4:

type Router struct { ... }

func NewRouter(e *Echo) *Router
func (e *Echo) Router() *Router

v5:

type DefaultRouter struct { ... }

func NewRouter(config RouterConfig) *DefaultRouter
func (e *Echo) Router() Router  // Returns interface

Changes:

  • New Router interface introduced
  • DefaultRouter is the concrete implementation
  • NewRouter() now takes RouterConfig instead of *Echo
  • Added NewConcurrentRouter(r Router) Router for thread-safe routing

4. Route Return Types Changed

v4:

func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route
func (e *Echo) Any(path string, h HandlerFunc, m ...MiddlewareFunc) []*Route
func (e *Echo) Routes() []*Route

v5:

func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo
func (e *Echo) Any(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo
func (e *Echo) Match(...) Routes  // Returns Routes type
func (e *Echo) Router() Router  // Returns interface

New Types:

type RouteInfo struct {
    Name       string
    Method     string
    Path       string
    Parameters []string
}

type Routes []RouteInfo  // Collection with helper methods

Impact: 🔴 BREAKING CHANGE

  • Route registration methods return RouteInfo instead of *Route
  • New Routes collection type with filtering methods
  • Route struct still exists but used differently

5. Response Type Changed

v4:

func (c Context) Response() *Response
type Response struct {
    Writer http.ResponseWriter
    Status int
    Size   int64
    Committed bool
}
func NewResponse(w http.ResponseWriter, e *Echo) *Response

v5:

func (c *Context) Response() http.ResponseWriter
type Response struct {
    http.ResponseWriter  // Embedded
    Status    int
    Size      int64
    Committed bool
}
func NewResponse(w http.ResponseWriter, logger *slog.Logger) *Response
func UnwrapResponse(rw http.ResponseWriter) (*Response, error)

Changes:

  • Context.Response() returns http.ResponseWriter instead of *Response
  • Response now embeds http.ResponseWriter
  • NewResponse takes *slog.Logger instead of *Echo
  • New UnwrapResponse() helper function

6. HTTPError Simplified

v4:

type HTTPError struct {
    Internal error
    Message  interface{}  // Can be any type
    Code     int
}

func NewHTTPError(code int, message ...interface{}) *HTTPError

v5:

type HTTPError struct {
    Code    int
    Message string  // Now string only
    // Has unexported fields (Internal moved)
}

func NewHTTPError(code int, message string) *HTTPError
func (he HTTPError) Wrap(err error) error  // New method
func (he *HTTPError) StatusCode() int      // Implements HTTPStatusCoder

Changes:

  • Message field changed from interface{} to string
  • NewHTTPError() now takes string instead of ...interface{}
  • Added HTTPStatusCoder interface and StatusCode() method
  • Added Wrap(err error) method for error wrapping

7. HTTPErrorHandler Signature Changed

v4:

type HTTPErrorHandler func(err error, c Context)

func (e *Echo) DefaultHTTPErrorHandler(err error, c Context)

v5:

type HTTPErrorHandler func(c *Context, err error)  // Parameters swapped!

func DefaultHTTPErrorHandler(exposeError bool) HTTPErrorHandler  // Now a factory

Impact: 🔴 BREAKING CHANGE

  • Parameter order reversed: (c *Context, err error) instead of (err error, c Context)
  • DefaultHTTPErrorHandler is now a factory function that returns HTTPErrorHandler
  • Takes exposeError bool to control error message exposure

Notable API Changes in v5

1. Generic Parameter Extraction Functions (Updated Signatures)

These helpers keep the same generic API but now accept *Context, and the form helpers are renamed from FormParam* to FormValue*:

// Query Parameters
func QueryParam[T any](c *Context, key string, opts ...any) (T, error)
func QueryParamOr[T any](c *Context, key string, defaultValue T, opts ...any) (T, error)
func QueryParams[T any](c *Context, key string, opts ...any) ([]T, error)
func QueryParamsOr[T any](c *Context, key string, defaultValue []T, opts ...any) ([]T, error)

// Path Parameters
func PathParam[T any](c *Context, paramName string, opts ...any) (T, error)
func PathParamOr[T any](c *Context, paramName string, defaultValue T, opts ...any) (T, error)

// Form Values
func FormValue[T any](c *Context, key string, opts ...any) (T, error)
func FormValueOr[T any](c *Context, key string, defaultValue T, opts ...any) (T, error)
func FormValues[T any](c *Context, key string, opts ...any) ([]T, error)
func FormValuesOr[T any](c *Context, key string, defaultValue []T, opts ...any) ([]T, error)

// Generic Parsing
func ParseValue[T any](value string, opts ...any) (T, error)
func ParseValueOr[T any](value string, defaultValue T, opts ...any) (T, error)
func ParseValues[T any](values []string, opts ...any) ([]T, error)
func ParseValuesOr[T any](values []string, defaultValue []T, opts ...any) ([]T, error)

FormParam* was renamed to FormValue*; the rest keep names but now take *Context.

Supported Types:

  • bool, string
  • int, int8, int16, int32, int64
  • uint, uint8, uint16, uint32, uint64
  • float32, float64
  • time.Time, time.Duration
  • BindUnmarshaler, encoding.TextUnmarshaler, json.Unmarshaler

Example Usage:

// v5 - Type-safe parameter binding
id, err := echo.PathParam[int](c, "id")
page, err := echo.QueryParamOr[int](c, "page", 1)
tags, err := echo.QueryParams[string](c, "tags")

2. Context Store Helpers Now Use *Context

// Type-safe context value retrieval
func ContextGet[T any](c *Context, key string) (T, error)
func ContextGetOr[T any](c *Context, key string, defaultValue T) (T, error)

// Error types
var ErrNonExistentKey = errors.New("non existent key")
var ErrInvalidKeyType = errors.New("invalid key type")

These helpers existed in v4 with Context and now accept *Context.

Example:

// v5
user, err := echo.ContextGet[*User](c, "user")
count, err := echo.ContextGetOr[int](c, "count", 0)

3. PathValues Type

New structured path parameter handling:

type PathValue struct {
    Name  string
    Value string
}

type PathValues []PathValue

func (p PathValues) Get(name string) (string, bool)
func (p PathValues) GetOr(name string, defaultValue string) string

// Context methods
func (c *Context) PathValues() PathValues
func (c *Context) SetPathValues(pathValues PathValues)

4. Time Parsing Options

type TimeLayout string

const (
    TimeLayoutUnixTime      = TimeLayout("UnixTime")
    TimeLayoutUnixTimeMilli = TimeLayout("UnixTimeMilli")
    TimeLayoutUnixTimeNano  = TimeLayout("UnixTimeNano")
)

type TimeOpts struct {
    Layout          TimeLayout
    ParseInLocation *time.Location
    ToInLocation    *time.Location
}

5. StartConfig for Server Configuration

type StartConfig struct {
    Address         string
    HideBanner      bool
    HidePort        bool
    CertFilesystem  fs.FS
    TLSConfig       *tls.Config
    ListenerNetwork string
    ListenerAddrFunc func(addr net.Addr)
    GracefulTimeout  time.Duration
    OnShutdownError  func(err error)
    BeforeServeFunc  func(s *http.Server) error
}

func (sc StartConfig) Start(ctx context.Context, h http.Handler) error
func (sc StartConfig) StartTLS(ctx context.Context, h http.Handler, certFile, keyFile any) error

Example:

// v5 - More control over server startup
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer cancel()

sc := echo.StartConfig{
    Address:         ":8080",
    GracefulTimeout: 10 * time.Second,
}
if err := sc.Start(ctx, e); err != nil {
    log.Fatal(err)
}

6. Echo Config and Constructors

type Config struct {
    // Configuration for Echo (logger, binder, renderer, etc.)
}

func NewWithConfig(config Config) *Echo

This adds a configuration struct for creating an Echo instance without mutating fields after New().


7. Enhanced Routing Features

// New route methods
func (e *Echo) AddRoute(route Route) (RouteInfo, error)
func (e *Echo) Middlewares() []MiddlewareFunc
func (e *Echo) PreMiddlewares() []MiddlewareFunc
type AddRouteError struct{ ... }

// Routes collection with filters
type Routes []RouteInfo

func (r Routes) Clone() Routes
func (r Routes) FilterByMethod(method string) (Routes, error)
func (r Routes) FilterByName(name string) (Routes, error)
func (r Routes) FilterByPath(path string) (Routes, error)
func (r Routes) FindByMethodPath(method string, path string) (RouteInfo, error)
func (r Routes) Reverse(routeName string, pathValues ...any) (string, error)

// RouteInfo operations
func (r RouteInfo) Clone() RouteInfo
func (r RouteInfo) Reverse(pathValues ...any) string

8. Middleware Configuration Interface

type MiddlewareConfigurator interface {
    ToMiddleware() (MiddlewareFunc, error)
}

Allows middleware configs to be converted to middleware without panicking.


9. New Context Methods

// v5 additions
func (c *Context) FileFS(file string, filesystem fs.FS) error
func (c *Context) FormValueOr(name, defaultValue string) string
func (c *Context) InitializeRoute(ri *RouteInfo, pathValues *PathValues)
func (c *Context) ParamOr(name, defaultValue string) string
func (c *Context) QueryParamOr(name, defaultValue string) string
func (c *Context) RouteInfo() RouteInfo

10. Virtual Host Support

func NewVirtualHostHandler(vhosts map[string]*Echo) *Echo

Creates an Echo instance that routes requests to different Echo instances based on host.


11. New Binder Functions

func BindBody(c *Context, target any) error
func BindHeaders(c *Context, target any) error
func BindPathValues(c *Context, target any) error  // Renamed from BindPathParams
func BindQueryParams(c *Context, target any) error

Top-level binding functions that work with *Context.


12. New echotest Package

package echotest // import "github.com/labstack/echo/v5/echotest"

func LoadBytes(t *testing.T, name string, opts ...loadBytesOpts) []byte
func TrimNewlineEnd(bytes []byte) []byte
type ContextConfig struct{ ... }
type MultipartForm struct{ ... }
type MultipartFormFile struct{ ... }

Helpers for loading fixtures and constructing test contexts.


Removed APIs in v5

Constants

// v4 - Removed in v5
const CONNECT = http.MethodConnect  // Use http.MethodConnect directly

Reason: Deprecated in v4, use stdlib http.Method* constants instead.


Constants Added in v5

// v5 additions
const (
    NotFoundRouteName = "echo_route_not_found_name"
)

Error Variable Changes

v4 exports:

ErrBadRequest
ErrInvalidKeyType
ErrNonExistentKey

v5 exports:

ErrBadRequest  // Now backed by unexported httpError type
ErrValidatorNotRegistered  // New
ErrInvalidKeyType
ErrNonExistentKey

Reason: v5 centralizes on NewHTTPError(code, message) rather than a broad set of predefined HTTP error variables.


Functions Removed

// v4 - Removed in v5
func GetPath(r *http.Request) string  // Use r.URL.Path or r.URL.RawPath

Variables Removed

// v4 - Removed in v5
var MethodNotAllowedHandler = func(c Context) error { ... }
var NotFoundHandler = func(c Context) error { ... }

Functions Renamed

// v4
func FormParam[T any](c Context, key string, opts ...any) (T, error)
func FormParamOr[T any](c Context, key string, defaultValue T, opts ...any) (T, error)
func FormParams[T any](c Context, key string, opts ...any) ([]T, error)
func FormParamsOr[T any](c Context, key string, defaultValue []T, opts ...any) ([]T, error)

// v5
func FormValue[T any](c *Context, key string, opts ...any) (T, error)
func FormValueOr[T any](c *Context, key string, defaultValue T, opts ...any) (T, error)
func FormValues[T any](c *Context, key string, opts ...any) ([]T, error)
func FormValuesOr[T any](c *Context, key string, defaultValue []T, opts ...any) ([]T, error)

Type Methods Removed/Changed

Echo struct changes:

// v4 fields removed in v5
type Echo struct {
    StdLogger        *stdLog.Logger  // Removed
    Server           *http.Server    // Removed (use StartConfig)
    TLSServer        *http.Server    // Removed (use StartConfig)
    Listener         net.Listener    // Removed (use StartConfig)
    TLSListener      net.Listener    // Removed (use StartConfig)
    AutoTLSManager   autocert.Manager // Removed
    ListenerNetwork  string          // Removed
    OnAddRouteHandler func(...)      // Changed to OnAddRoute
    DisableHTTP2      bool           // Removed (use StartConfig)
    Debug             bool           // Removed
    HideBanner        bool           // Removed (use StartConfig)
    HidePort          bool           // Removed (use StartConfig)
}

// v5 Echo struct (simplified)
type Echo struct {
    Binder           Binder
    Filesystem       fs.FS  // NEW
    Renderer         Renderer
    Validator        Validator
    JSONSerializer   JSONSerializer
    IPExtractor      IPExtractor
    OnAddRoute       func(route Route) error  // Simplified
    HTTPErrorHandler HTTPErrorHandler
    Logger           *slog.Logger  // Changed from Logger interface
}

Context interface → struct:

// v4
type Context interface {
    // Had: SetResponse(*Response)
    Response() *Response

    // Had: ParamNames(), SetParamNames(), ParamValues(), SetParamValues()
    // These are removed in v5 (use PathValues() instead)
}

// v5
type Context struct {
    // Concrete struct with unexported fields
}

func (c *Context) Response() http.ResponseWriter  // Changed return type
func (c *Context) PathValues() PathValues         // Replaces ParamNames/Values

Types removed:

// v4
type Map map[string]interface{}

Group changes:

// v4
func (g *Group) File(path, file string)  // No return value
func (g *Group) Static(pathPrefix, fsRoot string)  // No return value
func (g *Group) StaticFS(pathPrefix string, filesystem fs.FS)  // No return value

// v5
func (g *Group) File(path, file string, middleware ...MiddlewareFunc) RouteInfo
func (g *Group) Static(pathPrefix, fsRoot string, middleware ...MiddlewareFunc) RouteInfo
func (g *Group) StaticFS(pathPrefix string, filesystem fs.FS, middleware ...MiddlewareFunc) RouteInfo

Now return RouteInfo and accept middleware.


Value Binder Factory Name Changes

// v4
func PathParamsBinder(c Context) *ValueBinder
func QueryParamsBinder(c Context) *ValueBinder
func FormFieldBinder(c Context) *ValueBinder

// v5
func PathValuesBinder(c *Context) *ValueBinder  // Renamed
func QueryParamsBinder(c *Context) *ValueBinder
func FormFieldBinder(c *Context) *ValueBinder

Type Signature Changes

Binder Interface

// v4
type Binder interface {
    Bind(i interface{}, c Context) error
}

// v5
type Binder interface {
    Bind(c *Context, target any) error  // Parameters swapped!
}

DefaultBinder Methods

// v4
func (b *DefaultBinder) Bind(i interface{}, c Context) error
func (b *DefaultBinder) BindBody(c Context, i interface{}) error
func (b *DefaultBinder) BindPathParams(c Context, i interface{}) error

// v5
func (b *DefaultBinder) Bind(c *Context, target any) error  // Swapped params
// BindBody, BindPathParams, etc. are now top-level functions

JSONSerializer Interface

// v4
type JSONSerializer interface {
    Serialize(c Context, i interface{}, indent string) error
    Deserialize(c Context, i interface{}) error
}

// v5
type JSONSerializer interface {
    Serialize(c *Context, target any, indent string) error
    Deserialize(c *Context, target any) error
}

Renderer Interface

// v4
type Renderer interface {
    Render(io.Writer, string, interface{}, Context) error
}

// v5
type Renderer interface {
    Render(c *Context, w io.Writer, templateName string, data any) error
}

Parameters reordered with Context first.


NewBindingError

// v4
func NewBindingError(sourceParam string, values []string, message interface{}, internalError error) error

// v5
func NewBindingError(sourceParam string, values []string, message string, err error) error

Message parameter changed from interface{} to string.


HandlerName

// v5 only
func HandlerName(h HandlerFunc) string

New utility function to get handler function name.


Middleware Package Changes

Signature and Type Updates

// CORS now accepts optional allow-origins
func CORS(allowOrigins ...string) echo.MiddlewareFunc

// BodyLimit now accepts bytes
func BodyLimit(limitBytes int64) echo.MiddlewareFunc

// DefaultSkipper now uses *echo.Context
func DefaultSkipper(c *echo.Context) bool

// Trailing slash configs renamed/split
func AddTrailingSlashWithConfig(config AddTrailingSlashConfig) echo.MiddlewareFunc
func RemoveTrailingSlashWithConfig(config RemoveTrailingSlashConfig) echo.MiddlewareFunc
type AddTrailingSlashConfig struct{ ... }
type RemoveTrailingSlashConfig struct{ ... }

// Auth + extractor signatures now use *echo.Context and add ExtractorSource
type BasicAuthValidator func(c *echo.Context, user string, password string) (bool, error)
type Extractor func(c *echo.Context) (string, error)
type ExtractorSource string
type KeyAuthValidator func(c *echo.Context, key string, source ExtractorSource) (bool, error)
type KeyAuthErrorHandler func(c *echo.Context, err error) error

// BodyDump handler now includes err
type BodyDumpHandler func(c *echo.Context, reqBody []byte, resBody []byte, err error)

// ValuesExtractor now returns extractor source and CreateExtractors takes a limit
type ValuesExtractor func(c *echo.Context) ([]string, ExtractorSource, error)
func CreateExtractors(lookups string, limit uint) ([]ValuesExtractor, error)
type ValueExtractorError struct{ ... }

// New constants
const KB = 1024

// Rate limiter store now takes a float64 limit
func NewRateLimiterMemoryStore(rateLimit float64) (store *RateLimiterMemoryStore)

Added Middleware Exports

var ErrInvalidKey = echo.NewHTTPError(http.StatusUnauthorized, "invalid key")
var ErrKeyMissing = echo.NewHTTPError(http.StatusUnauthorized, "missing key")
var RedirectHTTPSConfig = RedirectConfig{ ... }
var RedirectHTTPSWWWConfig = RedirectConfig{ ... }
var RedirectNonHTTPSWWWConfig = RedirectConfig{ ... }
var RedirectNonWWWConfig = RedirectConfig{ ... }
var RedirectWWWConfig = RedirectConfig{ ... }

Removed/Consolidated Middleware Exports

// Removed in v5
func Logger() echo.MiddlewareFunc
func LoggerWithConfig(config LoggerConfig) echo.MiddlewareFunc
func Timeout() echo.MiddlewareFunc
func TimeoutWithConfig(config TimeoutConfig) echo.MiddlewareFunc
type ErrKeyAuthMissing struct{ ... }
type CSRFErrorHandler func(err error, c echo.Context) error
type LoggerConfig struct{ ... }
type LogErrorFunc func(c echo.Context, err error, stack []byte) error
type TargetProvider interface{ ... }
type TrailingSlashConfig struct{ ... }
type TimeoutConfig struct{ ... }

Also removed defaults: DefaultBasicAuthConfig, DefaultBodyDumpConfig, DefaultBodyLimitConfig, DefaultCORSConfig, DefaultDecompressConfig, DefaultGzipConfig, DefaultLoggerConfig, DefaultRedirectConfig, DefaultRequestIDConfig, DefaultRewriteConfig, DefaultTimeoutConfig, DefaultTrailingSlashConfig.


Router Interface Changes

v4 Router (Concrete Struct)

type Router struct { ... }

func NewRouter(e *Echo) *Router
func (r *Router) Add(method, path string, h HandlerFunc)
func (r *Router) Find(method, path string, c Context)
func (r *Router) Reverse(name string, params ...interface{}) string
func (r *Router) Routes() []*Route

v5 Router (Interface + DefaultRouter)

type Router interface {
    Add(routable Route) (RouteInfo, error)
    Remove(method string, path string) error
    Routes() Routes
    Route(c *Context) HandlerFunc
}

type DefaultRouter struct { ... }

func NewRouter(config RouterConfig) *DefaultRouter
func NewConcurrentRouter(r Router) Router  // NEW

type RouterConfig struct {
    NotFoundHandler           HandlerFunc
    MethodNotAllowedHandler   HandlerFunc
    OptionsMethodHandler      HandlerFunc
    AllowOverwritingRoute     bool
    UnescapePathParamValues   bool
    UseEscapedPathForMatching bool
}

Key Changes:

  • Router is now an interface
  • DefaultRouter is the concrete implementation
  • Add() returns (RouteInfo, error) instead of being void
  • New Remove() method
  • New Route() method replaces Find()
  • Configuration through RouterConfig

Echo Instance Method Changes

Route Registration

// v4
func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route

// v5
func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) RouteInfo
func (e *Echo) AddRoute(route Route) (RouteInfo, error)  // NEW

Static File Serving

// v4
func (e *Echo) Static(pathPrefix, fsRoot string) *Route
func (e *Echo) StaticFS(pathPrefix string, filesystem fs.FS) *Route
func (e *Echo) File(path, file string, m ...MiddlewareFunc) *Route
func (e *Echo) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) *Route

// v5
func (e *Echo) Static(pathPrefix, fsRoot string, middleware ...MiddlewareFunc) RouteInfo
func (e *Echo) StaticFS(pathPrefix string, filesystem fs.FS, middleware ...MiddlewareFunc) RouteInfo
func (e *Echo) File(path, file string, middleware ...MiddlewareFunc) RouteInfo
func (e *Echo) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo

Return type changed from *Route to RouteInfo.

Server Management

// v4
func (e *Echo) Start(address string) error
func (e *Echo) StartTLS(address string, certFile, keyFile interface{}) error
func (e *Echo) StartAutoTLS(address string) error
func (e *Echo) StartH2CServer(address string, h2s *http2.Server) error
func (e *Echo) StartServer(s *http.Server) error
func (e *Echo) Shutdown(ctx context.Context) error
func (e *Echo) Close() error
func (e *Echo) ListenerAddr() net.Addr
func (e *Echo) TLSListenerAddr() net.Addr
func (e *Echo) DefaultHTTPErrorHandler(err error, c Context)

// v5
func (e *Echo) Start(address string) error  // Simplified
func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request)

// Removed: StartTLS, StartAutoTLS, StartH2CServer, StartServer
// Use StartConfig instead for advanced server configuration
// Removed: Shutdown, Close, ListenerAddr, TLSListenerAddr
// Removed: DefaultHTTPErrorHandler (now a top-level factory function)

v5 provides StartConfig type for all advanced server configuration.

Router Access

// v4
func (e *Echo) Router() *Router
func (e *Echo) Routers() map[string]*Router  // For multi-host
func (e *Echo) Routes() []*Route
func (e *Echo) Reverse(name string, params ...interface{}) string
func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string
func (e *Echo) URL(h HandlerFunc, params ...interface{}) string
func (e *Echo) Host(name string, m ...MiddlewareFunc) *Group

// v5
func (e *Echo) Router() Router  // Returns interface
// Removed: Routers(), Reverse(), URI(), URL(), Host()
// Use router.Routes() and Routes.Reverse() instead

NewContext Changes

// v4
func (e *Echo) NewContext(r *http.Request, w http.ResponseWriter) Context
func NewResponse(w http.ResponseWriter, e *Echo) *Response

// v5
func (e *Echo) NewContext(r *http.Request, w http.ResponseWriter) *Context
func NewContext(r *http.Request, w http.ResponseWriter, opts ...any) *Context  // Standalone
func NewResponse(w http.ResponseWriter, logger *slog.Logger) *Response

Migration Guide Summary

If you are using Linux you can migrate easier parts like that:

find . -type f -name "*.go" -exec sed -i 's/ echo.Context/ *echo.Context/g' {} +
find . -type f -name "*.go" -exec sed -i 's/echo\/v4/echo\/v5/g' {} +

or in your favorite IDE

Replace all:

  1. echo.Context -> *echo.Context
  2. echo/v4 -> echo/v5

1. Update All Handler Signatures

// Before
func MyHandler(c echo.Context) error { ... }

// After
func MyHandler(c *echo.Context) error { ... }

2. Update Logger Usage

// Before
e.Logger.Info("Server started")
c.Logger().Error("Something went wrong")

// After
e.Logger.Info("Server started")
c.Logger().Error("Something went wrong")  // Same API, different logger

3. Use Type-Safe Parameter Extraction

// Before
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)

// After
id, err := echo.PathParam[int](c, "id")

4. Update Error Handler

// Before
e.HTTPErrorHandler = func(err error, c echo.Context) {
    // handle error
}

// After
e.HTTPErrorHandler = func(c *echo.Context, err error) {  // Swapped!
    // handle error
}

// Or use factory
e.HTTPErrorHandler = echo.DefaultHTTPErrorHandler(true)  // exposeError=true

5. Update Server Startup

// Before
e.Start(":8080")
e.StartTLS(":443", "cert.pem", "key.pem")

// After
// Simple
e.Start(":8080")

// Advanced with graceful shutdown
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
sc := echo.StartConfig{Address: ":8080"}
sc.Start(ctx, e)

6. Update Route Info Access

// Before
routes := e.Routes()
for _, r := range routes {
    fmt.Println(r.Method, r.Path)
}

// After
routes := e.Router().Routes()
for _, r := range routes {
    fmt.Println(r.Method, r.Path)
}

7. Update HTTPError Creation

// Before
return echo.NewHTTPError(400, "invalid request", someDetail)

// After
return echo.NewHTTPError(400, "invalid request")

8. Update Custom Binder

// Before
type MyBinder struct{}
func (b *MyBinder) Bind(i interface{}, c echo.Context) error { ... }

// After
type MyBinder struct{}
func (b *MyBinder) Bind(c *echo.Context, target any) error { ... }  // Swapped!

9. Path Parameters

// Before
names := c.ParamNames()
values := c.ParamValues()

// After
pathValues := c.PathValues()
for _, pv := range pathValues {
    fmt.Println(pv.Name, pv.Value)
}

10. Response Access

// Before
resp := c.Response()
resp.Header().Set("X-Custom", "value")

// After
c.Response().Header().Set("X-Custom", "value")  // Returns http.ResponseWriter

// To get *echo.Response
resp, err := echo.UnwrapResponse(c.Response())

Go Version Requirements

  • v4: Go 1.24.0 (per go.mod)
  • v5: Go 1.25.0 (per go.mod)

Generated by comparing go doc output from master (v4.15.0) and v5 (v5.0.0-alpha) branches