Check out how OpenResty XRay helps organizations troubleshoot issues and optimize the performance of their applications.

Learn More LIVE DEMO

This tutorial demonstrates how to share data across different HTTP requests served by an OpenResty application. We cover two approaches: Lua module-level variables for sharing within a single worker process, and lua_shared_dict for sharing across all worker processes. This is part of the OpenResty Tutorial series — if you are new to OpenResty, start with the Hello World HTTP Example first.

Setting Up the Project

cd ~/
mkdir data-share
cd data-share/
mkdir conf logs lua
tree

screenshot 1

We first prepare our test application’s directory tree.

Method 1: Lua Module-Level Variables

The easiest way to share data among requests is to use a custom Lua module named lua/my-module.lua.

We make the following edits:

  1. We add a global counter variable on the top-level of this module.
  2. Then we always increment this counter in a module function named main.
  3. and return the new counter value.
local _M = {}

local counter = 0

function _M.main()
    counter = counter + 1
    return counter
end

return _M

screenshot 6

Configuring Nginx

Now let’s quickly craft the nginx configuration file, conf/nginx.conf.

We make the following edits:

  1. Here we specify where to look for our Lua module.
  2. Then define a server listening on the local 8080 port.
  3. And a root location with content_by_lua_block.
  4. Load up our Lua module and invoke its main function.
  5. And output the returned counter value as the response body.
worker_processes 1;

events {
    worker_connections 1024;
}

http {
    lua_package_path "$prefix/lua/?.lua;;";

    server {
        listen 8080;

        location / {
            default_type text/plain;
            content_by_lua_block {
                local mod = require "my-module"
                local cnt = mod.main()
                ngx.say("counter = ", cnt)
            }
        }
    }
}

screenshot 13

Let’s check the directory tree again.

tree .

screenshot 15

Looking good.

Starting and Testing

Start this OpenResty application without sudo.

openresty -p $PWD/

screenshot 17

Here we only enable a single worker process.

ps aux|grep nginx|grep -v tmp

screenshot 18

Send an HTTP request to the server using curl:

curl 'http://127.0.0.1:8080/'

screenshot 19

The counter value is 1.

Again.

screenshot 21

Cool, it’s 2 now.

It will only keep growing.

screenshot 23

How It Works: Upvalues and the LuaJIT VM

This counter Lua variable is shared because it is an upvalue of the Lua module function.

cat lua/my-module.lua

screenshot 24

And the Lua module is cached and shared in the global LuaJIT virtual machine.

resty -Ilua -e 'require "my-module" print(package.loaded["my-module"].main)'

screenshot 25

See? We can also access the cached Lua module directly.

The package.loaded global table holds all the loaded Lua modules.

resty -e 'for k, v in pairs(package.loaded) do print(k) end'

screenshot 27

Here, most of the modules are those standard ones.

Limitation: Data Is Not Shared Across Worker Processes

Such data cannot be shared among different nginx worker processes.

screenshot 29

It’s not a problem here because only 1 worker process is configured.

But usually we would utilize multiple CPU cores by enabling multiple worker processes.

worker_processes 4;

screenshot 31

Then each worker process would have its own counter.

Let’s test the configuration and then reload the server.

openresty -p $PWD/ -t
kill -HUP `cat logs/nginx.pid`

screenshot 33

Now we should have 4 worker processes.

ps aux|grep nginx|grep -v tmp

screenshot 34

Choosing the Right Approach

The two sharing mechanisms serve different use cases:

Lua Module Variablelua_shared_dict
ScopeSingle worker processAll worker processes
Value typesAny Lua typeString, number, boolean
Typical useConfig cache, per-worker LRU cacheCounters, rate limiting, shared flags
Survives HUP reloadNoYes
Survives restartNoNo
Atomic operationsN/AYes (incr, add, set)

The Lua module approach is mostly useful for Lua-level data caching. The resty.lrucache Lua module shipped with OpenResty is designed for such use cases.

restydoc resty.lrucache

screenshot 36

We will cover this module in a future tutorial.

Method 2: Sharing Data Across Workers with lua_shared_dict

To share a counter across all worker processes, declare a shared memory zone with lua_shared_dict in the http block and access it via ngx.shared.DICT (to understand how these zones actually consume RAM under the hood, see How OpenResty and Nginx Shared Memory Zones Consume RAM):

http {
    lua_shared_dict my_counter 1m;

    server {
        listen 8080;

        location / {
            default_type text/plain;
            content_by_lua_block {
                local dict = ngx.shared.my_counter
                local newval, err = dict:incr("counter", 1)
                if not newval then
                    dict:add("counter", 0)
                    newval = dict:incr("counter", 1)
                end
                ngx.say("counter = ", newval)
            }
        }
    }
}

This counter increments correctly regardless of how many worker processes are running, and its value survives an HUP reload. The full ngx.shared.DICT API — including expiry (ttl), eviction behavior, and list operations — will be covered in a dedicated tutorial.

restydoc -s lua_shared_dict
restydoc -s ngx.shared.DICT

screenshot 38

That’s all I’d like to cover today. Happy hacking!

If you like this tutorial, please subscribe to this blog site and our YouTube channel. Thank you!

This tutorial is part of the OpenResty Tutorial series, a step-by-step guide from installation through production-ready techniques. Continue with Streaming HTTP Response Output in OpenResty.

About The Author

Yichun Zhang (Github handle: agentzh), is the original creator of the OpenResty® open-source project and the CEO of OpenResty Inc..

Yichun is one of the earliest advocates and leaders of “open-source technology”. He worked at many internationally renowned tech companies, such as Cloudflare, Yahoo!. He is a pioneer of “edge computing”, “dynamic tracing” and “machine coding”, with over 22 years of programming and 16 years of open source experience. Yichun is well-known in the open-source space as the project leader of OpenResty®, adopted by more than 40 million global website domains.

OpenResty Inc., the enterprise software start-up founded by Yichun in 2017, has customers from some of the biggest companies in the world. Its flagship product, OpenResty XRay, is a non-invasive profiling and troubleshooting tool that significantly enhances and utilizes dynamic tracing technology. And its OpenResty Edge product is a powerful distributed traffic management and private CDN software product.

As an avid open-source contributor, Yichun has contributed more than a million lines of code to numerous open-source projects, including Linux kernel, Nginx, LuaJIT, GDB, SystemTap, LLVM, Perl, etc. He has also authored more than 60 open-source software libraries.