OpenResty + Lua: An Old Choice, Reconsidered in the AI Era
OpenResty + Lua: An Old Choice, Reconsidered in the AI Era
OpenResty isn’t new. It’s nginx bolted onto LuaJIT, letting you drop Lua into each phase of the request lifecycle. I’ve leaned on it for years, as an API gateway and as the front layer for a datafeed. The reason I’m writing about it again in 2026 isn’t nostalgia. It’s that under the new assumption of AI helping write the code, its old shape suddenly makes a lot of sense.
The old battlefield: thin, controllable, light on resources
War stories first, so this doesn’t read like a sales pitch. The one that stuck with me was rewriting a gateway that had been running on a heavyweight runtime. C did the plumbing, Lua did the business logic, and at the same throughput it used roughly a tenth of the resources. No magic involved. The division of labour is just clean: connection handling, TLS, buffering, all the grubby work, gets done by nginx in C, and you only slot your own decisions into phases like access_by_lua and content_by_lua. A thin sheet of business logic sitting on a core that already knows how to push bytes around.
The detail lives in small places. Get client_max_body_size wrong and a large payload is either turned away at the door or swallowed whole until a worker falls over. Don’t reconnect to the upstream on every request; open a connection pool once in init_worker_by_lua and share it for the worker’s lifetime, which matters most with something like MySQL where short-lived connections are expensive. Inside Docker, use host networking, because the NAT layer on a bridge quietly shaves off throughput under load, the kind of loss you never notice until you actually run a stress test. None of this is textbook knowledge. It’s what traffic teaches you after you ship.
I’ve put it in front of reporting workloads too: OpenResty receiving, aggregating, and rate-limiting at the edge, with Cassandra landing the data behind it, and the middle layer written in Lua so it bends faster than redeploying a whole service. The sweet spot is obvious once you’ve seen it. A thin layer, one responsibility, close to the network.
Why it’s worth a second look in 2026
The abstractions in modern frameworks have piled up over the years. Front end, back end, same story: a single feature hides several layers of convention and several ways to write it, and the same task grows into entirely different shapes across two projects. Those abstractions were designed for human fingers, to save typing and cut repetition. The trouble is that once the bulk of the writing shifts to AI, that premise loosens.
Fragmented style is a tax on AI. Same framework, wired up one way here and another way there, and the model first has to guess which convention you’re standing on before it can carry on. Lua and C are the opposite: single semantics, fixed style, fewer things you can do and therefore fewer ways to do them. A model handles a language like that far more steadily than one with a sprawling ecosystem and divergent idioms, because there’s little to guess; write it the way the language already wants and it tends to come out right.
My view is this. Rather than teaching AI to imitate a human driving some bloated framework, hand it a clean-syntax environment with clear boundaries and let the business logic settle into a predictable, closed core. OpenResty’s phased hooks happen to offer exactly that shape: each phase has an obvious job, and Lua doesn’t give you many tricks to misuse. Keep the core tidy, let the AI work inside it, and your review gets easier too, because there simply isn’t much room for it to drift.
But you still have to own the lower layer. Lua’s metatable is the floor of its whole object model; metamethods like __index and __newindex decide how lookup and assignment actually flow. You can let AI write the business code on top, but this layer of the protocol is yours to understand, or one day the behaviour won’t match your mental model and you won’t even know where to start digging. AI-friendly doesn’t mean hands-off below. If anything it’s the reverse: the clearer the floor, the more freely you can let it move upstairs.
Pragmatic, without the hype
OpenResty is no silver bullet. You manage the coroutines yourself, and ngx.thread used carelessly gives you the situation where you think things run in parallel but are actually wedged. Stability needs care too: one stuck stretch of Lua wedges the whole worker with it. It’s the wrong tool for heavy stateful business logic; put that behind it and let OpenResty stick to the thin layer it’s good at.
It is old. Genuinely old. But along the axis of thin, controllable, and AI-friendly, that old shape is right. Shallow abstraction, a clear responsibility per layer, a language that doesn’t show off; seen from 2026, those traits wear better than frameworks that only grow thicker. If you want a quick start, I’ve left a 2026 template at openresty-template, same idea as that earlier docker template, clone it and start poking.
Takeaways
- OpenResty’s value is the clean split: the grubby work goes to nginx’s C core, the business logic is a thin sheet of Lua on top, and resource use stays low.
- The real detail lives at the boundaries:
client_max_body_size, theinit_worker_by_luaconnection pool, Docker host networking, all things you only learn in production. - Modern framework abstractions were built for human fingers, and fragmented style becomes a liability once AI does the writing.
- Lua and C have single semantics and a fixed style, so the model doesn’t guess conventions, and a closed core reviews more easily.
- AI-friendly isn’t hands-off; own the lower-layer protocol like the metatable, because the clearer the floor, the more freely you let AI work above it.
Sheng’s take, drafted with Claude · part of the 2026-06-13 blog renovation, paint still drying.