HomeIris
BSD-3-Clause
Web framework for Go

Iris, the batteries-included web framework for Go

iris.NewBuilder assembles an application through 8 interfaces, and each one hands back a narrower one, so a step called out of turn fails the build rather than the deploy.

Expressive routing with typed path parameters, one place to configure error handling, dependency injection that keeps handlers testable, and 31 middleware packages in the same module. Written by Gerasimos Maropoulos and maintained at Hellenic Development.

go get github.com/kataras/iris/v14@latest

Go 1.27 or newer. Licensed BSD-3-Clause, and always has been.

25,568
GitHub stars
2,425
Forks
2016
First release

Star and fork counts read from the GitHub API on 2026-09-21.

The compiler is the first reviewer

What the chain looks like, and what it refuses

On the left, a production application in one expression. On the right, the same chain with one step out of order. Nothing runs. Nothing gets as far as a test.

Builds

main.go
iris.NewBuilder().
    Prefix("/api").
    AllowOrigin("*").
    Compression(true).
    LogRequests(true).
    Health(true, "production", "kataras").
    Errors(errors.NewOptions().
        MapErrors(errors.NotFound, catalog.ErrNotFound)).
    Services(catalog.NewRepository, catalog.NewService).
    RouterMiddlewares().
    Middlewares().
    API("/products", api.NewProductsAPI).
    Build().
    Listen(":8080")

CORS, compression, access logs, a health endpoint, the error map, your services and your API groups. One expression, checked at compile time.

Does not build

main.go
iris.NewBuilder().
    Prefix("/api").
    API("/products", api.NewProductsAPI). // not yet
    Build()
Terminal
$ go build ./...
./main.go:12:35: iris.NewBuilder().Prefix("/api").API undefined
	(type iris.CorsBuilder has no field or method API)

Prefix returns a CorsBuilder, which exposes AllowOrigin and Cors. There is no API method on it to call.

The builder

8 interfaces, and the compiler holds the order

The builder does not hand back one object with forty methods on it. Each step returns a different interface, and that interface exposes only the steps that are still legal. Follow it down and the aperture closes.

  1. Builderreturns CorsBuilder8 of 8 steps still open
    PrefixNoPrefix

    Where an application starts. Mount everything under a path, or say out loud that you are not.

  2. CorsBuilderreturns CompressionBuilder7 of 8 steps still open
    AllowOriginCors

    The prefix is settled, so origins are the only question left open.

  3. CompressionBuilderreturns RequestLoggingBuilder6 of 8 steps still open
    Compression

    One decision, one method. gzip, deflate, br, snappy, s2 and zstd.

  4. RequestLoggingBuilderreturns HealthBuilder5 of 8 steps still open
    LogRequestsLogRequestsWith

    Access logging on or off, or hand it an accesslog you configured yourself.

  5. HealthBuilderreturns ServiceBuilder4 of 8 steps still open
    HealthNoHealth

    Declining is a method too, so a missing health endpoint is a decision rather than an oversight.

  6. ServiceBuilderreturns MiddlewareBuilder3 of 8 steps still open
    Errors (self)Deferrables (self)Services

    The error map, the shutdown closers, and the constructors the container will call for you.

  7. MiddlewareBuilderreturns APIBuilder2 of 8 steps still open
    RouterMiddlewares (self)Middlewares

    Before the router, then after it. Two lists, and the order between them is not yours to get wrong.

  8. APIBuilderreturns *Application1 of 8 steps still open
    API (self)Build

    Register controllers until you are done. Build hands back the application, ready to Listen.

In practice

And then handlers get short

products_api.go
func (api *ProductsAPI) create(ctx iris.Context) {
    input, ok := ctx.BindJSON[catalog.ProductInput]()
    if !ok {
        return // 400 already written: malformed JSON or failed Validate.
    }

    id, err := api.svc.Create(ctx, input)
    ctx.Created(id, err) // 201, or the centrally mapped error.
}

Decoding, validation and error rendering are configured once, at the top of the application. This handler is six lines because the other twenty live somewhere else, in one place, where they can all be changed at once.

ctx.BindJSON has already written the 400 by the time it returns false, whether the body was malformed or the type's own Validate method rejected it. The payload type is spelled in the call and checked by the compiler, a shape Go 1.27's generic methods made possible; Iris is the first Go web framework to require 1.27 and build its API on it.

ctx.Created writes the 201, or looks the error up in the central map and writes whatever that map says a client is allowed to see.

Neither needs a branch here, which is the whole point of putting them there.

Streaming, and the AI backends built on it

The parts of a live response that break in production

Server-Sent Events are three lines of Fprintf until something buffers them, a write deadline ends the answer mid-sentence, or a client disappears without closing the connection and the work runs on for nobody. The sse package handles those, and ai puts a model's output on top of it. The error branch is the same one every other handler uses.

  • Nothing commits until the first Send. An authorization check that fails after Open still returns an ordinary status code with an ordinary body.
  • That first event unbuffers the response. Compression and the recorder an access log installs step aside, the absolute write timeout is cleared, and the headers that stop a proxy buffering go out.
  • A 15s heartbeat notices a client that vanished. Without a write that fails, a closed lid stays invisible for about fifteen minutes of TCP retransmission. The interval is the largest one that survives nginx, an AWS load balancer, Cloudflare and Heroku at once.
  • One handler serves both AI shapes. Streaming when the request asks for it, one JSON document when it does not, with nothing in between changing.
stream.go
stream, err := sse.Open(ctx) // writes nothing yet.
if errors.HandleError(ctx, err) {
    return
}
defer stream.Close(nil) // the terminal frame, on success too.

for token := range tokens {
    if err := stream.Send(sse.Event{Name: "token", Data: []byte(token)}); err != nil {
        return // the client is gone.
    }
}
What ships in the core

Six things you do not have to assemble

Each of these is a decision the framework has already made, in the place where making it once is cheaper than making it in every handler.

Routing that rejects bad input first

20 typed path parameter types, plus macros and constraints of your own. A request that does not match the type never reaches your handler, so the first line of the handler is not a validation check.

One place for errors

Canonical error codes, one wire format, and a single map from Go error to HTTP response. Handlers return errors and the map decides what a client sees. Internals do not leak out through a stack trace.

Dependency injection that stays testable

Constructors declare what they need and the container provides it. Startup hooks run before the first request and closers run on shutdown, without either being wired by hand.

Payloads that validate themselves

Give a request type a Validate method and ctx.BindJSON runs it after decoding. A handler that receives a value can trust the value, which is what lets the handler stay short.

Tests with no ports and no sleeps

The httptest helpers run your real router, your real middleware chain and your real error map in process. No network, no waiting for a server to come up, and no flakes to re-run.

Secure defaults you did not have to find

Session cookies ship Secure and SameSite=Lax. JWT is read from the Authorization header only. Wildcard CORS will not carry credentials. The hardened setting is the one you get by doing nothing.

Authentication at every scale

One-line Basic Auth, a generic JWT SDK, and, in the same module, a complete identity server with an OAuth2 provider. That server is what Hellenic Identity runs: the admin panel at id.hellenic.dev administers an Iris application.

In the tree, not in your go.mod

31 middleware packages ship with the framework

Every one of these is versioned with Iris and tested against it. The builder installs several of them for you, and the rest are one import away.

accesslogapikeybasicauthbodylimitcachecompresscorscountergeolocationgrpchcaptchahttpcosti18nipaccessjwtmethodoverridemodrevisionmonitorpprofraterecaptcharecorderrecoveryreferrerrequestidrewriteservertimingsessionsversioningviewwebsocket

Compression covers gzip, deflate, br, snappy, s2 and zstd. What each package does, and 65 runnable examples in 12 topics, are in the repository.

Learning Iris

The documentation is a book, and the book is free

Iris does not have a documentation site and a separate book to buy. It has one book, published as chapters you read online and as a single PDF, and both are free. It is The Professional Guide to the Iris Web Framework for Go, now in its fifth edition: 24 chapters and 19 diagrams across 432 pages, from a first route to a tested application in production.

Every example in it is verified against the framework source rather than remembered, which is a harder promise than it sounds and the reason the book is versioned alongside the code. No registration, no email address, and no payment.

Edition
Fifth Edition
Chapters
24
Pages
432
Upgrading

Coming from v12

Change the import path to github.com/kataras/iris/v14, then work through the compiler's error list. Every v12 name that v14 removed fails at compile time, so the task list writes itself.

Three defaults are stricter than v12. Read these before you deploy.

  • Session cookies now ship with Secure and SameSite=Lax.
  • JWT is read from the Authorization header only.
  • CORS no longer advertises credentials alongside a wildcard origin.

Packages moved too: sessions, i18n, view and websocket now live under middleware, and the view engine implementations moved out to the separate iris-contrib/views repository.

Read the migration guide
Who stands behind it

Ten years in the open

Iris has been developed in public since 2016, funded by the people who use it: 379 sponsors to date, counted on 2026-09-16. The record is all here, and every claim on this page is checkable in one of these.

Speed is the number people ask for, and it is the one this page does not print. The project maintains its own benchmark suite at kataras/server-benchmarks, written and run by the same person who wrote the framework. That makes it public and reproducible, not independent, and it should not be read as independent. The harness, the handlers and the raw results are all in that repository. Run it on your own hardware before it decides anything.

Start with the builder

One go get, one chain of 8 steps, and an HTTP service answering requests. The compiler checks the wiring on the way.

Iris: common questions

What is the Iris web framework?

Iris is an open-source web framework for Go, built in the open since 2016. It gives an API or a website expressive routing with 20 typed path parameter types, one place to configure error handling, dependency injection that keeps handlers testable, and production defaults that are secure out of the box. The framework is built on Go generics: an application builder the compiler checks step by step, typed request helpers that validate a payload before a handler sees it, and controllers resolved by the dependency container. Iris ships 31 middleware packages in the same module, covering access logs, sessions, JWT, CORS, rate limiting, compression, and WebSockets. It is licensed BSD-3-Clause and written by Gerasimos Maropoulos at Hellenic Development.

Is Iris production ready?

Iris has been in continuous development since 2016, and the current release is 14.0.0. Its defaults are set for production rather than for a demo: session cookies ship with Secure and SameSite=Lax, JWT is read from the Authorization header only, and CORS will not advertise credentials alongside a wildcard origin. The BSD-3-Clause license places no restriction on commercial use, and there is no paid tier to reach for later. Go 1.27 or later is required. The source, the changelog, and the full issue history are public at github.com/kataras/iris, which is the most direct way to judge its maturity for your own workload.

How does Iris compare to Gin, Echo, and Fiber?

Iris, Gin, Echo, and Fiber are all HTTP frameworks for Go, and the difference that matters in practice is scope rather than routing speed. Iris carries more of the application inside the framework: an application builder whose step order the compiler enforces, dependency injection, typed request helpers that validate a payload before the handler runs, one error map that turns a domain error into a response, and 31 middleware packages in the same module. Iris is also the first Go web framework to require Go 1.27: request binding is a generic method the compiler checks (a shape older toolchains cannot express), and every JSON request and response runs on the standard library's new encoding/json/v2 rather than a bundled third-party encoder. Gin, Echo, and Fiber stay closer to a router plus middleware, which is less to learn and less to carry. Pick Iris when you want those pieces without assembling them, and pick a smaller framework when you want a minimal core. For speed, the project maintains its own benchmark suite at github.com/kataras/server-benchmarks. Run it against your own workload.

How do I install Iris?

Install Iris by running go get github.com/kataras/iris/v14@latest inside a Go module, then import github.com/kataras/iris/v14. Iris requires Go 1.27 or later and nothing else: no code generator, no CLI to install first, and no runtime beyond the binary the Go toolchain produces. The major version stays in the import path under the standard Go module rules, so a v12 and a v14 dependency can sit in one build while a codebase moves across. The API reference is published at pkg.go.dev/github.com/kataras/iris/v14, the documentation is at iris-go.com, and the repository carries 65 runnable examples grouped by topic, from getting started and routing through dependency injection, controllers, authentication, and testing.

How do I upgrade from Iris v12 to v14?

Upgrading changes the import path from github.com/kataras/iris/v12 to github.com/kataras/iris/v14, and every v12 name that v14 removed fails at compile time, so the compiler writes the task list for you. The repository ships a migration guide mapping each removed name to its replacement, and describes the work as bringing a v12 application forward in one sitting. Three defaults are stricter than they were in v12 and are worth reading before you deploy: session cookies ship with Secure and SameSite=Lax, JWT is read from the Authorization header only, and CORS will not advertise credentials alongside a wildcard origin. Packages moved as well, with sessions, i18n, view, and websocket now under middleware, and the view engine implementations in the separate iris-contrib/views repository. Go 1.27 or later is required. The guide is at https://github.com/kataras/iris/blob/main/MIGRATION.md.