Framework
panjf2000/gnet avatar
panjf2000/gnet

panjf2000/gnet: an event-driven Go networking framework built on epoll and kqueue

🚀 gnet is a high-performance, lightweight, non-blocking, event-driven networking framework written in pure Go.

11,248 stars1,119 forksGoApache-2.0

At a glance

What is it?
gnet replaces the goroutine-per-connection model of Go's net package with a reactor of event loops, and it is explicit that it is an alternative for performance-critical transport work rather than a general replacement. This review covers what it does, how to install it, where it stops, and what to check before adopting it.
Who is it for?
Adopt gnet when you are writing a transport-layer server in Go and the goroutine-per-connection cost of net is the thing you are trying to remove: gnet gives you TCP, UDP, Unix Domain Socket, edge-triggered I/O and three load-balancing algorithms behind a small interface.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 83 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem gnet removes: one goroutine per connection

Go's net package makes concurrency easy by giving each connection its own goroutine. That model is pleasant to write against and expensive to run at scale: every connection carries a stack, and the runtime scheduler has to move all of them. gnet takes the opposite position. Its README states that gnet and net "don't share the same philosophy in network programming" and that the two cannot be reconciled. Instead of a goroutine per socket, gnet runs a set of event loops, each owning a group of connections, and drives them with epoll on Linux or kqueue on BSD and macOS.

The intended audience is narrow and specific. gnet works at the transport layer with TCP, UDP and Unix Domain Socket, and the README frames it as a base on which you implement your own application-layer protocol: "you get an HTTP Server if you implement HTTP protocol upon gnet while you have a Redis Server done with the implementation of Redis protocol upon gnet". If you want an HTTP server out of the box, this is not it. If you are building a game gateway, a proxy, a message broker or a custom binary protocol, the trade-off starts to make sense. The README also says gnet is not meant to displace net and does not plan to become a coverall framework, which is an unusually honest scope statement for a project of this kind.

How the event loops, reactor and goroutine pool fit together

The repository layout shows the mechanism clearly. There are paired platform files throughout: acceptor_unix.go and acceptor_windows.go, connection_linux.go and connection_bsd.go, eventloop_unix.go and eventloop_windows.go, listener_unix.go and listener_windows.go. The reactor itself appears twice, as reactor_default.go and reactor_ultimate.go, which implies a build-tag choice between two event-loop implementations rather than one. The README describes the model as "event-driven looping based on a networking model of multiple threads/goroutines" and says the runtime is lock-free.

On top of the loops sit several pieces worth naming. A goroutine pool, powered by the ants library, handles work that should not block an event loop. Buffers come in three shapes: ring buffer, linked-list buffer and elastic mixed buffer, described as "efficient, reusable, and elastic". Load balancing across event loops offers Round-Robin, Source-Addr-Hash and Least-Connections. Edge-triggered I/O is supported, multiple network addresses can be bound, and new connections can be registered to event loops at runtime.

That combination defines the programming model you have to accept. Because a connection belongs to a loop rather than a goroutine, per-connection state is not protected by the scheduler, and anything slow inside a callback stalls every other connection on that loop. The ants pool exists precisely because that is a real hazard. Whether the README gives you enough guidance on which callbacks may block is a fair question; it lists the pool as a feature rather than explaining when to reach for it.

Installing gnet and running a first server

gnet is distributed as a Go module. The README recommends using it through Go Modules and says that with modules enabled you can add the import and let the toolchain fetch dependencies. The module path is versioned, so v2 lives at github.com/panjf2000/gnet/v2. The badge in the README states a minimum Go version of 1.20, and go.mod agrees with a `go 1.20` directive.

bash
go get -u github.com/panjf2000/gnet/v2

That command pulls gnet and its dependencies. The README also documents the v1 path as `go get -u github.com/panjf2000/gnet`; new code should use the v2 module, since the repository's default branch and go.mod are both on v2.

Once the module is in your dependency graph, the import line is what ties your code to it. The README gives this as the entry point:

go
import "github.com/panjf2000/gnet/v2"

After adding it, run `go mod tidy` or a build command and the necessary dependencies download automatically. What you should see is the module resolved in go.mod at a v2 version, with ants, bytebufferpool, zap, golang.org/x/sync and golang.org/x/sys appearing as requirements. If your build fails on a Go version constraint, the cause is likely the pinned x/sync and x/sys versions, which go.mod annotates with the comment that newer releases require Go 1.23 or later. The README does not walk through writing an event handler in the excerpt available here; the documentation for the API surface is pointed at pkg.go.dev.

What gnet does not do: TLS, io_uring and production Windows

The roadmap is short and it is the most useful part of the README for anyone making an adoption decision. Three items are unchecked: TLS support, io_uring support and KCP support. TLS being absent is the one that changes architecture. A gnet server that needs TLS has to terminate it elsewhere, in a proxy or a load balancer, or the application has to layer it on itself, and the README offers no guidance on either path. For a framework aimed at performance-critical services, that is a significant gap, and it is worth checking whether the roadmap item has moved before you design around it.

The platform caveat is stated bluntly: "Windows version of gnet should only be used in development for developing and testing, it shouldn't be used in production." Windows support exists, with its own acceptor, connection, eventloop and listener files, but it is not presented as production-grade. The README does not explain which mechanism the Windows build uses in place of epoll or kqueue, and it does not document rollback or fallback behaviour if an event loop fails.

There is also a scope limit that is easy to miss. gnet provides what the README calls "only the core functionality" required by a network application. It is not a protocol library. If your problem is HTTP routing, WebSocket framing or Redis command parsing, gnet gives you the socket and the loop and nothing above them. Choosing gnet means committing to write that layer.

gnet against Go net, and against the libuv family

The nearest alternative is Go's own net package, and the difference is architectural rather than cosmetic. net gives each connection a goroutine and lets the runtime scheduler handle blocking reads and writes; gnet gives each connection to an event loop and expects callbacks to return quickly. The consequence is that net code ports to gnet only by rewriting the concurrency model, not by swapping an import. The README is explicit that the philosophies cannot be reconciled, so this is not a drop-in replacement and should not be treated as one.

Outside Go, the README names libuv, Netty, Twisted and Tornado as projects that "work in a similar pattern as gnet under the hood". The practical difference is the language boundary: those frameworks put the event loop in C, Java or Python, and your handler code lives in the same runtime as the loop. gnet keeps everything in Go, which means the goroutine pool and the Go scheduler are still available for the work you offload from the loop. It also means you inherit Go's garbage collector on the hot path, which is the cost that a C event loop does not pay.

The README also notes that gnet derives from the evio project, with higher performance and more features claimed. If you are already on evio, the migration question is whether you need the added pieces (client support, the load-balancing algorithms, the buffer variants) badly enough to move.

Maintenance, releases and what the licence allows

The repository is not archived, and the last push was on 2026-07-09. The most recent release is v2.10.0, tagged 2026-07-03 and named Steins;Gate, following v2.9.0 in June 2025 and v2.8.0 in May 2025. So the cadence is irregular: two releases landed within about two weeks of each other in mid-2025, then roughly a year passed before v2.10.0. That pattern is worth knowing if you depend on upstream fixes arriving quickly.

Upgrade cost is shaped by go.mod. The dependency set is small and mostly stable: ants v2.12.1, bytebufferpool v1.0.0, zap v1.28.0, lumberjack v2.2.1, plus testify for tests. The two entries that matter are golang.org/x/sync and golang.org/x/sys, both carrying inline comments warning against upgrading past v0.11.0 and v0.30.0 respectively because newer releases require Go 1.23 or later. That pin is a deliberate compatibility choice and it means a future gnet release that raises the Go floor will also lift those pins. Plan for a toolchain bump, not just a module bump.

gnet is licensed under Apache-2.0, which permits commercial and closed-source use and includes an explicit patent grant. It also requires that you preserve copyright and licence notices and state significant changes if you redistribute modified source. This is a description of the licence text, not legal advice; if you are embedding gnet in a product with unusual distribution terms, have counsel read the NOTICE and attribution requirements.

Editorial conclusion

Adopt gnet when you are writing a transport-layer server in Go and the goroutine-per-connection cost of net is the thing you are trying to remove: gnet gives you TCP, UDP, Unix Domain Socket, edge-triggered I/O and three load-balancing algorithms behind a small interface. Do not adopt it if you need TLS today (it is an unchecked roadmap item), if you need a full HTTP stack, or if you intend to run the Windows build in production, which the README says should be for development and testing only. Before you commit, verify three things in the repository: that your toolchain is Go 1.20 or newer, that the pinned golang.org/x/sync v0.11.0 and golang.org/x/sys v0.30.0 versions are acceptable in your dependency graph, and that the event-loop model matches how your protocol handles per-connection state.

Frequently asked questions

What is the gnet network framework?

gnet is an event-driven networking framework written in pure Go, built on epoll and kqueue, that works at the transport layer with TCP, UDP and Unix Domain Socket. It is designed as an alternative to Go's net package for performance-critical services rather than a general replacement for it.

How do I install gnet in a Go project?

Add the v2 module with `go get -u github.com/panjf2000/gnet/v2`, then import "github.com/panjf2000/gnet/v2" in your code and run go mod tidy or a build command so dependencies download. The README states a minimum Go version of 1.20.

Which platforms can gnet run on?

The README lists Linux, macOS, Windows and the BSD variants Darwin, DragonFlyBSD, FreeBSD, NetBSD and OpenBSD. It also states that the Windows version should only be used in development for building and testing, not in production.

What load-balancing algorithms does gnet offer across event loops?

The README lists three: Round-Robin, Source-Addr-Hash and Least-Connections. They determine how incoming connections are distributed across the event loops in the reactor.

Official sources

  1. License: Apache-2.0
  2. panjf2000/gnet on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/panjf2000-gnet.svg)](https://hysenlabs.com/projects/panjf2000-gnet)