# Echo > Echo is a high performance, extensible, minimalist Go web framework built on the standard `net/http` library. Echo adds a fast radix-tree router, request binding with pluggable validator, a deep middleware ecosystem, centralized error handling, and template rendering on top of the standard library. Import path: `github.com/labstack/echo/v5` Go version: 1.25+ Handler signature: `func(c *echo.Context) error` ## Context `Context` is a concrete struct passed by pointer to all handlers. ```go type Context struct { ... } // Handlers receive *echo.Context func handler(c *echo.Context) error { ... } ``` ### Context methods ```go c.Request() *http.Request c.SetRequest(r *http.Request) c.Response() http.ResponseWriter c.SetResponse(rw http.ResponseWriter) c.IsTLS() bool c.IsWebSocket() bool c.Scheme() string c.RealIP() string c.Path() string c.SetPath(path string) c.RouteInfo() RouteInfo c.Param(name string) string c.ParamOr(name, defaultValue string) string c.PathValues() PathValues c.SetPathValues(pathValues PathValues) c.QueryParam(name string) string c.QueryParamOr(name, defaultValue string) string c.QueryParams() []string c.QueryString() string c.FormValue(name string) string c.FormValueOr(name, defaultValue string) string c.FormValues() []string c.FormFile(name string) (*multipart.FileHeader, error) c.MultipartForm() (*multipart.Form, error) c.Cookie(name string) (*http.Cookie, error) c.SetCookie(cookie *http.Cookie) c.Cookies() []*http.Cookie c.Get(key string) any c.Set(key string, val any) c.Bind(i any) error c.Validate(i any) error c.Render(code int, name string, data any) error c.HTML(code int, html string) error c.HTMLBlob(code int, b []byte) error c.String(code int, s string) error c.JSON(code int, i any) error c.JSONPretty(code int, i any, indent string) error c.JSONBlob(code int, b []byte) error c.JSONP(code int, callback string, i any) error c.JSONPBlob(code int, callback string, i any) error c.XML(code int, i any) error c.XMLPretty(code int, i any, indent string) error c.XMLBlob(code int, b []byte) error c.Blob(code int, contentType string, b []byte) error c.Stream(code int, contentType string, r io.Reader) error c.File(file string) error c.FileFS(file string, filesystem fs.FS) error c.Attachment(file, name string) error c.Inline(file, name string) error c.NoContent(code int) error c.Redirect(code int, url string) error c.Logger() *slog.Logger c.SetLogger(logger *slog.Logger) c.Echo() *Echo ``` ### Context store (type-safe) ```go c.Set("user", user) val, err := echo.ContextGet[*User](c, "user") count, err := echo.ContextGetOr[int](c, "count", 0) ``` ## Echo struct ```go type Echo struct { Binder Binder Filesystem fs.FS Renderer Renderer Validator Validator JSONSerializer JSONSerializer IPExtractor IPExtractor OnAddRoute func(route Route) error HTTPErrorHandler HTTPErrorHandler Logger *slog.Logger } ``` Constructor: `echo.New() *Echo` or `echo.NewWithConfig(config Config) *Echo` ## Echo methods ### Routing ```go e.GET(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo e.POST(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo e.PUT(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo e.DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo e.PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo e.HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo e.OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo e.ANY(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo e.Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) Routes e.RouteNotFound(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo e.AddRoute(route Route) (RouteInfo, error) ``` ### Middleware ```go e.Use(middleware ...MiddlewareFunc) e.Pre(middleware ...MiddlewareFunc) e.Middlewares() []MiddlewareFunc e.PreMiddlewares() []MiddlewareFunc ``` ### Groups ```go e.Group(prefix string, m ...MiddlewareFunc) *Group ``` ### Static files ```go e.Static(pathPrefix, fsRoot string, m ...MiddlewareFunc) RouteInfo e.StaticFS(pathPrefix string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo e.File(path, file string, m ...MiddlewareFunc) RouteInfo e.FileFS(file string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo ``` ### Server ```go e.Start(address string) error e.StartTLS(address string, certFile, keyFile any) error ``` ```go 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 } // StartConfig.Start and StartConfig.StartTLS for graceful shutdown sc := echo.StartConfig{Address: ":8080", GracefulTimeout: 10 * time.Second} sc.Start(ctx, e) ``` ## Error handling ```go // HTTPError with string message err := echo.NewHTTPError(http.StatusBadRequest, "invalid input") // Custom error handler (params: context pointer, then error) e.HTTPErrorHandler = func(c *echo.Context, err error) { // custom error handling } // Default error handler factory (exposeError bool) e.HTTPErrorHandler = echo.DefaultHTTPErrorHandler(true) ``` ```go echo.ErrBadRequest echo.ErrValidatorNotRegistered echo.ErrInvalidKeyType echo.ErrNonExistentKey ``` ## Logging Echo uses the standard library `log/slog` package. ```go e.Logger = slog.Default() c.Logger().Info("message", "key", "value") // Custom logger logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) e.Logger = logger ``` ## Router ```go // Router interface with DefaultRouter implementation func NewRouter(config RouterConfig) *DefaultRouter func (e *Echo) Router() Router // Thread-safe routing func NewConcurrentRouter(r Router) Router ``` ## RouteInfo ```go type RouteInfo struct { Name string Method string Path string Parameters []string } // Routes type with filtering methods type Routes []RouteInfo // Methods: FilterByMethod, FilterByName, FilterByPath, FindByMethodPath, Reverse ``` ## PathValues ```go 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 ``` ## Generic helper functions ```go echo.PathParam[T](c *Context, name string, opts ...any) (T, error) echo.PathParamOr[T](c *Context, name string, defaultValue T, opts ...any) (T, error) echo.QueryParam[T](c *Context, key string, opts ...any) (T, error) echo.QueryParamOr[T](c *Context, key string, defaultValue T, opts ...any) (T, error) echo.QueryParams[T](c *Context, key string, opts ...any) ([]T, error) echo.QueryParamsOr[T](c *Context, key string, defaultValue []T, opts ...any) ([]T, error) echo.FormValue[T](c *Context, key string, opts ...any) (T, error) echo.FormValueOr[T](c *Context, key string, defaultValue T, opts ...any) (T, error) echo.FormValues[T](c *Context, key string, opts ...any) ([]T, error) echo.FormValuesOr[T](c *Context, key string, defaultValue []T, opts ...any) ([]T, error) echo.ParseValue[T](value string, opts ...any) (T, error) echo.ParseValueOr[T](value string, defaultValue T, opts ...any) (T, error) echo.ParseValues[T](values []string, opts ...any) ([]T, error) echo.ParseValuesOr[T](values []string, defaultValue []T, opts ...any) ([]T, error) echo.ContextGet[T](c *Context, key string) (T, error) echo.ContextGetOr[T](c *Context, key string, defaultValue T) (T, error) ``` Supported generic types: bool, string, int/int8/int16/int32/int64, uint/uint8/uint16/uint32/uint64, float32/float64, time.Time, time.Duration, BindUnmarshaler, encoding.TextUnmarshaler, json.Unmarshaler ## Binding functions ```go echo.BindBody(c *Context, target any) error echo.BindHeaders(c *Context, target any) error echo.BindPathValues(c *Context, target any) error echo.BindQueryParams(c *Context, target any) error ``` ### Binder helpers ```go echo.PathValuesBinder(c *Context) *ValueBinder echo.QueryParamsBinder(c *Context) *ValueBinder echo.FormFieldBinder(c *Context) *ValueBinder ``` ## Group methods ```go g.Use(m ...MiddlewareFunc) g.Group(prefix string, m ...MiddlewareFunc) *Group g.GET(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo g.POST(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo g.PUT(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo g.DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo g.PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo g.ANY(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo g.Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) Routes g.Static(pathPrefix, fsRoot string, m ...MiddlewareFunc) RouteInfo g.StaticFS(pathPrefix string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo g.File(path, file string, m ...MiddlewareFunc) RouteInfo g.FileFS(file string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo ``` ## Built-in middleware | Middleware | Description | |---|---| | BasicAuth | HTTP basic authentication | | BodyDump | Dumps request and response bodies | | BodyLimit | Limits request body size | | Compress | Gzip response compression | | ContextTimeout | Request context timeout | | CORS | Cross-origin resource sharing | | CSRF | Cross-site request forgery protection | | Decompress | Gzip request decompression | | KeyAuth | Key-based authentication | | MethodOverride | HTTP method override | | Proxy | Reverse proxy | | RateLimiter | Rate limiting | | Recover | Panic recovery | | Redirect | HTTP redirect | | RequestID | Request ID header | | RequestLogger | Structured request logging | | Rewrite | URL rewriting | | Secure | Security headers | | Slash | Trailing slash handling | | Static | Static file serving | ## Wrapping stdlib handlers ```go echo.WrapHandler(h http.Handler) HandlerFunc echo.WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc ``` ## Virtual host ```go echo.NewVirtualHostHandler(vhosts map[string]*Echo) *Echo ``` ## echotest package ```go import "github.com/labstack/echo/v5/echotest" echotest.LoadBytes(t *testing.T, name string, opts ...loadBytesOpts) []byte echotest.TrimNewlineEnd(bytes []byte) []byte echotest.ContextConfig{...} echotest.MultipartForm{...} echotest.MultipartFormFile{...} ``` ## Complete server example ```go package main import ( "context" "log/slog" "net/http" "os" "os/signal" "syscall" "time" "github.com/labstack/echo/v5" "github.com/labstack/echo/v5/middleware" ) func main() { e := echo.New() e.Use(middleware.RequestLogger()) e.Use(middleware.Recover()) e.GET("/", func(c *echo.Context) error { return c.String(http.StatusOK, "Hello, World!") }) e.GET("/users/:id", func(c *echo.Context) error { id, err := echo.PathParam[int](c, "id") if err != nil { return echo.NewHTTPError(http.StatusBadRequest, "invalid user id") } return c.JSON(http.StatusOK, map[string]int{"id": id}) }) 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 { slog.Error("server error", "error", err) } } ```