# node-red-docker: the container images behind Node-RED

> Node-RED is a flow programming tool that people run in all sorts of ways, and the container images are what most of them run. The repository that builds them is small and mostly documentation, and the parts of it that are worth reading are the tag grammar, the choice between a small image and a smaller one, and the history of two decisions that were made once and are still visible in how the images behave.

**node-red/node-red-docker** — Repository for all things Node-RED and Docker related

- Repository: https://github.com/node-red/node-red-docker
- Stars: 539 · Forks: 436
- Language: Shell
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/node-red-node-red-docker

## What the repository is

The repository is described as the home for everything related to Node-RED and Docker, and its first job is to say what it does: it describes some of the many ways Node-RED can be run under Docker, and it provides builds for multiple processor architectures, the two most common ones on servers and on single board computers.

The readme also sets out its assumptions, and it is worth noticing that it does: some basic familiarity with Docker and the command line is assumed. That is a deliberate choice about the audience, and it is the right one, because everything in this repository is a container image and the documentation is about which image to pull and what is inside it, not about how containers work.

Then there is the distribution history, which is three sentences and explains the whole layout of the published artefacts.

Since version 1.0 of the tool, this project has provided the build for the container published on the main public registry. Since version 4.0.9 of the tool, the containers are also published to a second registry, the one hosted by the source hosting service, with the same tag names as on the first. And the much older images from the 0.20 series are still published, under a different name, for people who have not moved.

The second registry with identical tags is worth a moment. It means a deployment can move from one registry to the other by changing an image reference, which is a useful property for a project whose images are pulled by machines that somebody else configures. And keeping the old images under a different name rather than deleting them is the right call, because an image that disappears breaks every deployment that referenced it.

The project is Apache 2.0 licensed, and the release history shows two lines running in parallel, which is what you would expect for a container project: one line is the current version of the tool and the other is a maintained older line, both receiving fixes.

## The quick start, and what each part of it is doing

The readme's quick start is a single command, and then it takes the command apart, which is the most useful thing in the document.

        docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red

The first part runs the container, building it locally if necessary. The interactive flag attaches a terminal session so that you can see what is going on, which matters more here than for most images because this one logs its own startup sequence and you want to read it. The port flag connects a port on the host to the exposed port inside the container, and the numbers are the same on both sides because that is the port the editor listens on by default.

The volume flag is the one that matters. It mounts a host directory into the container's data directory, and the readme says why: so that any changes made to the flows are persisted. Without it, every restart of the container would give you an empty tool, and the flows you spent a day wiring would be gone. So the named volume is not a convenience, it is the difference between a scratchpad and an application.

The name flag gives the container a friendly local name, and the readme explains the reason in a sentence that is really about the ergonomics of the tool: by giving it a name you can manipulate it more easily, and by fixing the host port you know you are on familiar ground.

And then the honesty about the cost: you can only run one instance at a time, because the port is fixed. The readme acknowledges this and says one step at a time, which is the right attitude for a quick start whose purpose is to get one instance running in a minute.

The rest of the section is the operating manual, and it is short because the container lifecycle is the standard one. You detach the terminal with a two-key sequence and the container keeps running. You reattach to see the logs. You start it again after a reboot, and you stop it when you are finished.

And then the one flag that is specific to this image: a health check can be turned off with a flag, which tells you the image ships with a health check defined, and that somebody found a reason to want to disable it.

## The startup output, and the two warnings in it

The readme shows the whole startup sequence, and it is worth reading because two of the lines are warnings that a user will otherwise meet as surprises.

The sequence itself is the tool telling you about itself: the version of the tool, the version of the runtime, the kernel it is running on, the fact that it is loading the palette of nodes, where the settings file is, what the context store is and which module provides it, the user directory, and then the flows file, and then the creation of a new flows file because there was not one. The context store line is the interesting one for anybody who has run the tool outside a container: the default store is in memory, so the state that lives in the context does not survive a restart, and that is a deliberate default for a container where the durable state is the flows file and the credentials file.

The first warning is that the projects feature is disabled. That is a configuration choice in the image, and it exists because the projects feature writes to the user directory in a way that does not fit the container's layout.

The second warning is the important one, and it is a block of text about the credentials file.

The credentials file is encrypted using a system-generated key. If the system-generated key is lost for any reason, the credentials file will not be recoverable, and you will have to delete it and re-enter the credentials. You should set your own key using the credential secret option in the settings file, and the tool will then re-encrypt the credentials file using your chosen key the next time you deploy a change.

That is a warning with three parts and each part is a decision.

The first part is that encryption is on by default, which is right: the credentials file holds the passwords of the services your flows talk to, and in a container that file is in a volume on a host.

The second part is the warning about the generated key, and it exists because the key is generated and stored somewhere that a user may not know about. The fix is to set your own, which means the key lives somewhere you chose.

And the third part is the re-encryption on the next deploy, which is a small courtesy: the tool does not force you to re-enter your credentials, it re-encrypts the file with the key you chose. So the remedy is a one-line configuration change rather than an exercise in recovering data.

The output ends with the server running at a local address, and the readme then points at that address for the familiar desktop.

## The tag grammar, and the two sizes of image

The image variations section explains the naming convention, and the convention is the most useful thing in it because it makes the tag space legible.

A tag is the tool's version, then the runtime's version, then optionally the image type. And there are only two image types.

The default type has Python 2 and Python 3 and the development tools installed. The minimal type has no Python and no development tools.

And the readme says exactly what that costs: the minimal versions are not able to install nodes that require any locally compiled native code. Which is a real constraint and a completely reasonable trade, because the nodes that compile native code are the ones that need a toolchain, and the toolchain is the biggest thing in the image.

So the choice is between an image you can install anything into and an image that is much smaller. A user whose flows are all in the standard palette never notices the difference; a user who wants to install a node that compiles something does, immediately, and the readme's example shows the tag for the minimal variant in a run command.

```bash
docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red:latest-minimal
```

The architecture support is the other half of the section, and the manifest list mechanism is what makes it work. The images are published as manifest lists, so the architecture is detected automatically. The motivation the readme gives is a deployment that mixes single board computers and server processors, in a swarm, and a tag that resolves to the wrong architecture's image is exactly the failure this avoids.

And then the table, which is a small slice of the full matrix, showing the tool version, the runtime major version, the architecture, whether Python is present, whether the development tools are present, and the base image for each combination. The base image column is the one that matters for anybody who needs to extend the image, because that is the layer you inherit.

## The Alpine trade-off

The images are based on the official runtime images for a minimal Linux distribution, and the readme says the reason is to keep them as small as possible.

And then it says what that costs, which is the most honest paragraph in the document: using that distribution reduces the built image size, but removes the standard dependencies that are required for native module compilation.

So the whole image design is one decision and its consequences. Small images are worth having, and they are worth having most for the flows that run on a single board computer with a limited disk and a limited memory footprint. And the price is that anything needing a compiler is not there.

The readme then gives the two ways out, and the second is the better one. You can extend the image with the missing packages on the running container, which is quick and leaves you with an untracked change, or you can build a new image, and it points at a directory in the repository and at the documentation on the tool's own site for doing it properly.

That is a well-shaped escape hatch: the cheap way for a test, the correct way for production, and the documentation in the place where the tool's users look rather than only in the image repository.

There is a subtlety worth naming, because it is the kind of thing that bites in production. Installing a node that compiles native code into a running container works, and the compiled artefact is then part of the container's writable layer rather than part of the image, which means it disappears when the container is replaced. So the cheap way is fine for trying something out and wrong for a deployment that recreates its containers.

And the note about extending on the running container interacts with the volume mounting: the data directory is a volume, and the native module ends up in the user directory, which is inside the volume. So it may well survive a container replacement, depending on where the module is installed. Which is precisely the kind of detail that is worth knowing before you rely on it.

## The repository, and the two decisions with a history

The top level of the repository is small, and the file names are the interesting part.

There is a directory with the Docker build files, a directory of examples of custom images, and a flows file at the root, which is a sample flow that you can import to see the tool working with something in it. There is a separate document about volume changes, and a contributing guide, and the usual files.

The volume changes document is the more interesting of the two, and the readme explains why it exists. In version 1.2, the named volume was removed from the build. The readme says it should not affect many users, and points at the document for the details.

That is a decision with a history, and the reason such a document is needed at all is worth understanding. A named volume in a build file means the image declares a volume, and the container runtime creates it if it does not exist. The problem with that is that it happens silently, and the volume it creates is not the one a user might expect. Removing the declaration means the container's own filesystem is used unless the user explicitly mounts a volume, which is what the quick start does. The change makes the persistence explicit, and the price is that a user who relied on the implicit volume loses their data on upgrade, which is exactly why the details are written down.

The package manifest is the other file with a story in it. Its version matches the current tool version exactly, which is the convention for a repository whose version and whose image tags are the same thing. Its description is not about containers at all but about what the tool is, which tells you the manifest is inherited from the tool's own repository rather than written for this one. And it is a manifest with no dependencies and no scripts, which is what a package manifest for a repository that contains no code looks like.

The remaining files are the ones a container project always has: the attributes file for line endings, the ignore file, the directory of continuous integration configuration from the era when that was the norm, and the directory with the per-architecture build definitions.

And the last observation is about the release history. Two version lines are maintained in parallel, one current and one older, and the older one has a longer patch sequence. For a container image, a maintained old line is a promise to the people who upgraded late, and it is one of the more considerate things a project of this kind can do.

## Conclusion

The container images fit a team that runs a flow application in a container and wants it to work on whatever hardware it lands on, including a single board computer. It does not fit somebody who needs to install nodes with native code without extending the image first. Verify first which image variant you want, because the minimal one cannot install anything that compiles, that the volume you mount is where the flows and the credentials live, and that you set your own credential secret rather than leaving the generated one, since the log tells you plainly that the credentials cannot be recovered if the key is lost.

## FAQ

### What is the node-red-docker repository?

It is the repository that describes the ways to run Node-RED under Docker and that provides the builds for the published container images, with support for the two most common processor architectures. It assumes familiarity with Docker and the command line, and it is mostly documentation and build files rather than code.

### How do the Node-RED container tags work?

A tag is the Node-RED version, then the Node runtime major version, then optionally the image type. The image type is either the default, which has Python and the development tools installed, or minimal, which has neither and therefore cannot install nodes that require locally compiled native code.

### Why do the Node-RED images not install a compiler?

Because they are based on a minimal Linux distribution, and that is what keeps the images small. The cost is that the standard dependencies needed to compile native modules are absent, so a user who needs them has to extend the image or build a new one, and the readme points at both the examples in the repository and the documentation for doing it properly.

### What should I do about the credentials warning in the Node-RED startup output?

Set your own credential secret in the settings file rather than relying on the generated one. The tool tells you that the credentials file is encrypted with a system-generated key and that it cannot be recovered if that key is lost, and it re-encrypts the file with your key the next time you deploy a change.

### How do the Node-RED images handle multiple processor architectures?

They are published as manifest lists, so the architecture is detected automatically when the image is pulled. The readme gives the motivation as a deployment that mixes single board computers and server processors in a swarm, where a tag that resolved to the wrong architecture's image would be the failure to avoid.

## Sources

- [Issues](https://github.com/node-red/node-red-docker/issues)
- [License: Apache-2.0](https://github.com/node-red/node-red-docker/blob/main/LICENSE)
- [node-red/node-red-docker on GitHub](https://github.com/node-red/node-red-docker)
- [README](https://github.com/node-red/node-red-docker/blob/main/README.md)
- [Releases](https://github.com/node-red/node-red-docker/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/node-red-node-red-docker
