Open-Source Wikis

/

nginx

/

How to contribute

/

Patterns and conventions

nginx/nginx

Patterns and conventions

The nginx codebase has a strong, explicit style. Most of it is captured at nginx.org's development guide; this page summarizes the rules that come up most often in PR review.

Naming

Item Convention Example
Public symbol ngx_<area>_<thing> ngx_palloc, ngx_http_init_request
Type ngx_<thing>_t ngx_pool_t, ngx_str_t
Struct definition struct ngx_<thing>_s + typedef ... ngx_<thing>_t ngx_module_s / ngx_module_t
Module ngx_<area>_<name>_module ngx_http_proxy_module
Static helper static ngx_<area>_<verb>_<noun>(...) static ngx_http_get_indexed_variable
Macro NGX_<UPPER>_<UPPER> NGX_HTTP_OK, NGX_OK
Local variable short, lowercase c, r, cf, cln, pool

Short locals are idiomatic and reviewers won't ask for longer names. The standard short names:

Local Type
c ngx_connection_t *
r ngx_http_request_t *
cf ngx_conf_t *
cscf ngx_http_core_srv_conf_t *
clcf ngx_http_core_loc_conf_t *
cln ngx_pool_cleanup_t *
pool ngx_pool_t *
b ngx_buf_t *
cl, chain ngx_chain_t *
e ngx_http_script_engine_t *
u ngx_http_upstream_t *

Formatting

  • Indent: 4 spaces, no tabs
  • Line length: ~80 columns; the whitespace check enforces no trailing whitespace
  • Braces: K&R for functions (opening brace on its own line); for blocks (if, for, while, switch) the opening brace stays on the same line
static ngx_int_t
ngx_http_my_handler(ngx_http_request_t *r)
{
    ngx_int_t  rc;

    if (r->method != NGX_HTTP_GET) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_send_header(r);
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        return rc;
    }

    return NGX_OK;
}
  • Blank lines between local declarations and code — and locals are usually grouped/aligned by type.
  • Two blank lines between functions.
  • Comments: /* ... */ only. C++ // comments are not used in the source tree.

Strings

ngx_str_t is { size_t len; u_char *data; }not null-terminated.

ngx_str_t  name = ngx_string("hello");
ngx_str_t  empty = ngx_null_string;
ngx_str_t  buf;

ngx_str_set(&buf, "world");      /* sets len + data, data is a literal */

Beware:

  • data is u_char *, not char *. Cast at the boundary, or use ngx_strlow, ngx_strncasecmp, etc.
  • printf("%V", &str) is the formatter — not %s. The V specifier consumes a ngx_str_t *.
  • ngx_pnalloc(pool, len) allocates len bytes; ngx_pcalloc zeroes them.

Error handling

Most functions return one of:

#define  NGX_OK         0
#define  NGX_ERROR     -1
#define  NGX_AGAIN     -2
#define  NGX_BUSY      -3
#define  NGX_DONE      -4
#define  NGX_DECLINED  -5
#define  NGX_ABORT     -6

Patterns:

  • NGX_OK — success.
  • NGX_ERROR — fatal; finalize the request/connection.
  • NGX_AGAIN — would block, schedule yourself again.
  • NGX_DECLINED — "I don't handle this case, try the next module."
  • NGX_DONE — "the request is fully finalized, do nothing further."

HTTP handlers can also return one of the NGX_HTTP_* status macros (NGX_HTTP_OK, NGX_HTTP_FORBIDDEN, NGX_HTTP_INTERNAL_SERVER_ERROR, ...) which the request engine maps to either the response status or to the error_page machinery.

Errors are logged through ngx_log_error(level, log, errno, fmt, ...). Don't printf.

Memory ownership

Almost nothing is malloc'd. Allocate from a pool whose lifetime matches what you're producing:

Need Allocate from
Per-request data r->pool (HTTP) / s->connection->pool (Stream)
Per-connection data c->pool
Per-cycle (config) data cf->pool / cycle->pool
Cross-worker shared data A shared zone, allocated via ngx_slab_alloc

If you need to free something before the pool is destroyed (e.g., a file you opened, a regex you compiled), register a cleanup:

ngx_pool_cleanup_t  *cln;

cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_my_cleanup_t));
if (cln == NULL) {
    return NGX_ERROR;
}
cln->handler = ngx_my_cleanup_handler;
cln->data    = my_data;

Concurrency

Workers never share heap memory through threads inside a single worker — there's one event-loop thread per worker. Cross-worker state goes through:

  • Shared memory zones — set up at config time via ngx_shared_memory_add(), attached lazily per worker.
  • The slab allocator (ngx_slab.c) inside a shared zone, with ngx_shmtx_t locks for atomicity.
  • Atomics (ngx_atomic_*) for counters and simple flags.
  • ngx_rwlock_t for short-held reader/writer sections inside shared zones.

Modules that use the thread pool (aio threads, --with-threads) hand work off via ngx_thread_task_t and get a callback in the event loop when the worker thread finishes. There's no other shared-mutable-memory threading inside a single worker.

Modules: the standard skeleton

A new HTTP module typically defines:

static ngx_command_t  ngx_http_my_commands[] = { /* directive table */ };
static ngx_http_module_t  ngx_http_my_module_ctx = {
    NULL,                          /* preconfiguration */
    ngx_http_my_init,              /* postconfiguration: register handlers in phases */
    NULL, NULL,                    /* create main / init main conf */
    NULL, NULL,                    /* create srv  / merge srv  conf */
    ngx_http_my_create_loc_conf,   /* create location conf */
    ngx_http_my_merge_loc_conf,    /* merge location conf */
};
ngx_module_t  ngx_http_my_module = {
    NGX_MODULE_V1,
    &ngx_http_my_module_ctx,
    ngx_http_my_commands,
    NGX_HTTP_MODULE,
    NULL,                          /* init master */
    NULL,                          /* init module */
    NULL,                          /* init process */
    NULL,                          /* init thread */
    NULL,                          /* exit thread */
    NULL,                          /* exit process */
    NULL,                          /* exit master */
    NGX_MODULE_V1_PADDING
};

Read primitives/module for the full layout and systems/configuration for how directives become C state.

What gets pushed back at review

  • Magic numbers without #define
  • Missing error handling on a function that can fail
  • A malloc() or free() — should almost always be a pool allocation
  • A printf or fprintf — use ngx_log_error
  • A strncpy/strncat — use ngx_cpymem, ngx_copy, or pool-allocated buffers
  • A for (int i = ...) — declare the loop var separately (C89 habit; the project targets old compilers too)
  • Unbounded growth in a hot path — the event loop must remain bounded per iteration
  • A long subject line in the commit message — the linter will catch it but reviewers will too

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – nginx wiki | Factory