# Extension points — redis/redis

> Canonical page: https://codevetter.com/unpack/redis/extension-points

# Extension points — redis/redis

Scanned commit c3215f019a4c11c35d438f241114e94730fe39e5 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Redis has four first-class extension mechanisms. New commands are added declaratively: drop a JSON spec in `src/commands/`, implement the proc, and regenerate `src/commands.def`. New configuration parameters are appended to the `static_configs[]` table in `src/config.c` using the `create*Config` macro family. New runtime behaviour is added out-of-process via the module API (`RM_CreateCommand`/`RM_CreateSubcommand` plus data types, filters, and hooks). New scripting languages plug into `functionsRegisterEngine()`. On top of these, this tree adds a fifth: `modules/modules.yaml` as a declarative registry for bundled external modules.
- Command registration is codegen-driven: `src/commands/*.json` is the input, `utils/generate-command-code.py` is the generator, and `src/Makefile`'s rule `$(COMMANDS_DEF_FILENAME).def: commands/*.json ../utils/generate-command-code.py` regenerates `src/commands.def`. CI fails if the checked-in file drifts. — [src/Makefile#L503-504](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/Makefile#L503-L504) [utils/generate-command-code.py](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/utils/generate-command-code.py) [.github/workflows/ci.yml#L22-28](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/.github/workflows/ci.yml#L22-L28)
- The generator maps declarative JSON to C enums via `ARG_TYPES` (string/integer/double/key/pattern/unix-time/pure-token/oneof/block) and `GROUPS`, which already contains the newer `COMMAND_GROUP_ARRAY` and `COMMAND_GROUP_RATE_LIMIT` — adding a command group means editing this table. — [utils/generate-command-code.py#L7-40](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/utils/generate-command-code.py#L7-L40)
- The runtime command registry is `redisCommandTable[]` from commands.def, loaded once by `populateCommandTable()` into dicts consulted by `lookupCommandLogic()`, `lookupCommandBySds()` and `lookupCommandByCString()` — module commands are inserted into the same dicts. — [src/server.c#L3556-3570](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L3556-L3570) [src/server.c#L3675-3745](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L3675-L3745)
- Configuration is a single append-only table: `standardConfig static_configs[]` in src/config.c, populated by 119 `createBoolConfig`/`createStringConfig`/`createEnumConfig`/`createSDSConfig`/etc. calls, each taking a flags mask (`MODIFIABLE_CONFIG`, `IMMUTABLE_CONFIG`, `DEBUG_CONFIG`, `HIDDEN_CONFIG`, `SENSITIVE_CONFIG`) plus optional validate and apply callbacks. — [src/config.c#L3445-3490](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/config.c#L3445-L3490) [src/config.c#L3530-3531](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/config.c#L3530-L3531)
- Config apply-callbacks are the hook for cross-subsystem side effects — e.g. `updateClusterFlags` on `cluster-replica-no-failover`, `updateJemallocBgThread` on `jemalloc-bg-thread`, `updateAppendonly` on `appendonly`, `updateRequirePass` on `requirepass`, and `applyClusterBusPortProtectedMode`. — [src/config.c#L3445-3490](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/config.c#L3445-L3490) [src/config.c#L3530-3531](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/config.c#L3530-L3531)
- The module command API is `RM_CreateCommand(ctx, name, cmdfunc, strflags, firstkey, lastkey, keystep)` with `RM_CreateSubcommand(parent, ...)` for containers — the canonical way third-party code adds commands without touching the core tables. — [src/module.c#L1348](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/module.c#L1348) [src/module.c#L1479](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/module.c#L1479) [src/redismodule.h](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/redismodule.h)
- Modules can intercept every command before dispatch by registering a command filter, invoked as `moduleCallCommandFilters(c)` at the top of `processCommand()`; `src/module.c` documents a flag to prevent a module's own `RM_Call()` from re-entering its filter. — [src/server.c#L4671-4678](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L4671-L4678) [src/module.c#L11960-11975](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/module.c#L11960-L11975)
- Server lifecycle hooks are exposed as module server events — `beforeSleep()` fires `moduleFireServerEvent(REDISMODULE_EVENT_EVENTLOOP, REDISMODULE_SUBEVENT_EVENTLOOP_BEFORE_SLEEP, NULL)` once per loop iteration when `moduleCount()` is non-zero. — [src/server.c#L2024-2030](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L2024-L2030) [tests/unit/moduleapi/hooks.tcl](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/tests/unit/moduleapi/hooks.tcl) [tests/unit/moduleapi/eventloop.tcl](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/tests/unit/moduleapi/eventloop.tcl)
- Scripting languages are pluggable through `functionsRegisterEngine(const char *engine_name, engine *engine)`, which stores into a module-level `static dict *engines`; `FUNCTION STATS` reflects the registry back to clients, and the only current registration is `LUA_ENGINE_NAME` from `luaEngineInitEngine` in function_lua.c. — [src/functions.c#L99-100](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/functions.c#L99-L100) [src/functions.c#L407-420](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/functions.c#L407-L420) [src/functions.c#L455-465](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/functions.c#L455-L465) [src/function_lua.c#L512](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/function_lua.c#L512)
- Keyspace notification is a central hook point via `notifyKeyspaceEvent(type, event, key, dbid)` and the newer `notifyKeyspaceEventWithSubkeys(...)` — new data types must call these to participate in keyspace events and client-side-cache invalidation. — [src/notify.c#L276-285](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/notify.c#L276-L285)
- Connection types are a runtime-registered abstraction: `connTypeInitialize()` in `main()` sets up `server.listeners[j]` for `j < CONN_TYPE_MAX`, with implementations in `src/socket.c`, `src/unix.c` and `src/tls.c` behind `src/connection.h` — TLS can even be built as a loadable module with `BUILD_TLS=module`. — [src/server.c#L8336](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L8336) [src/connection.h](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/connection.h) [src/Makefile#L343-357](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/Makefile#L343-L357)
- Bundled external modules are added declaratively by appending an entry to `modules/modules.yaml` with `name`/`repo`/`ref`/`target_module`/`loadmodule` and optional `build_env` — no new Makefile is needed, because `modules/common.mk` derives `MODULE_NAME` from `$(notdir $(CURDIR))` and reads the rest from the manifest. — [modules/modules.yaml#L28-50](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/modules/modules.yaml#L28-L50) [modules/common.mk#L5-20](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/modules/common.mk#L5-L20) [modules/MODULES.md#L18-40](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/modules/MODULES.md#L18-L40)
- All YAML parsing has exactly one implementation: `scripts/lib/manifest.sh`, which is dual-mode — sourced as a shell library (`manifest_modules`, `manifest_field`, `manifest_ref`, `resolve_modules`) and invoked as a CLI by `modules/manifest.mk`. Extending the manifest format means editing that one file. — [modules/MODULES.md#L28-34](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/modules/MODULES.md#L28-L34) [scripts/lib/manifest.sh](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/scripts/lib/manifest.sh) [modules/manifest.mk](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/modules/manifest.mk)
- New top-level Make goals that take positional module names plug into the `GOALS_WITH_ARGS := <goal>:<VAR>` list in the root Makefile; the dispatch and no-op `.PHONY` targets are generated automatically by the `_capture_goal_args` define. — [Makefile#L36-70](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/Makefile#L36-L70)
- New Tcl test suites require no registration — dropping a `.tcl` file into `tests/unit/`, `tests/unit/type/`, `tests/unit/cluster/` or `tests/integration/` is enough, since `test_helper.tcl` globs those directories. The exception is `tests/unit/moduleapi/`, where `runtest-moduleapi` lists each suite explicitly with `--single`. — [tests/test_helper.tcl#L30-44](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/tests/test_helper.tcl#L30-L44) [runtest-moduleapi#L21-70](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/runtest-moduleapi#L21-L70)
- The embedded C test harness is extended through the `redisTests[]` table consumed by `getTestProcByName()` in `main()`, letting a data-structure file register a `redisTestProc` runnable as `redis-server test <name>`. — [src/server.c#L8268-8305](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L8268-L8305)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
