/usr/src/node-red/node_modules vs /data/node_modules with Docker

TLDR: If Node-Red installs npm packages auto-magically into /data/, what is the point of a custom docker image as base image/layer?


Details:
Firstly, congrats on the 3.x release!

I am trying to update/adapt my NR image to use the new Docker image base, but am running into some challenges (let me know if there is a more appropriate place to ask this).

As per the Docker Quick Start, I have a package.json (also tried manually npm install the needed packages). In the example Dockerfile provided, it uses...

COPY package.json .

Am I understanding correctly that this places that package.json in the already-defined/default WORKDIR (/usr/src/node-red)? This is where/how I was adding my extra npm packages (debugger, db libraries, etc).

When I docker compose ... up the image container, I see...

(snipped)...
[info] Installing module: pg, version: latest
[info] Installed module: pg
(snipped)...

So, even though the package/module was already installed and available, it gets installed again? The flows.json I am including does define this library (pg, for Postgresql) in a function's modules section (which is correct, yes?) This is at least in part why I see the output above, correct?

I extracted the default settings.js to enable the new runtime feature (which is disabled by default). I also plan to include auth info (which is also why I am not relying on the default baked-in version of settings.js). I mention this to explain there shouldn't be anything problematic in there.

If I docker exec -it mynodered sh into the running container...

~ $ pwd
/usr/src/node-red
~ $ npm ls --depth=0
node-red-docker@3.0.0 /usr/src/node-red
+-- @azure/cosmos@3.10.5
+-- node-red-contrib-actionflows@2.1.2
+-- node-red-contrib-friendly-id@0.2.1
+-- node-red-debugger@1.1.1
+-- node-red@3.0.0
`-- pg@8.6.0

~ $ cd /data/
/data $ npm ls --depth=0
node-red-project@0.0.1 /data
+-- @azure/cosmos@3.16.3
`-- pg@8.7.3

So, if despite my custom image built off nodered/node-red:3.0.0-16-minimal as the base, NR still populates a node_modules folder in the /data/ directory (which I am trying to avoid, as I am not wanting to use a volume map for the whole /data/ folder (nothing should change during runtime, once I get this straightened out).

This in part seems to be related to a new feature which automatically installs packages in NR 2.x or 3.x... but I am not certain I am understanding the distinction between the two paths (mentioned in title).

I am hoping to just need flows.json and settings.js need to be volume mapped onto the image into a running container.

Generally, I think that the /data/ folder will be user accessible. The docker image will not be. So if you want to have custom nodes installed and don't want users of nr to be able to mess with them, that would be a good way.

long story short:
/usr/src/node-red contains what they call "core modules"; these modules come as a bundle on the regular node-red installation. A base image is following also this pattern.
While /data/node-modules is the standard path that will contain any module not included on the node-red standard installation. You can adjust this path on the settings.js, using the userDir key.

Now: can you use the /usr/src/node-red for installing "your" modules and build a custom image?, I guess you can... BUT, if you decide to take that path for whatever reason, it means you will have to go through this process every-time the node-red core team updates the base image.

In my humble opinion, the way it's designed is way more effective and manageable.

The challenge is, this will be used on systems with little/no connectivity. Relying on a local /data/ volume mount seems less "portable" as well (including updates and changes in a build system is a relatively easy lift so I am much less concerned about that). Additionally, I have a local path that must be accessible to the flows (currently mapped to something like /data/subdir). I suppose I could map elsewhere (or make a location in a Dockerfile)?

The goal is to have an image with all the needed pieces "baked in" so to speak (such that, upon start, nothing further needs downloaded and is already present).

Maybe this will help explain the alternatives (as I understand them) and the challenges I am seeing with them...

Inputs

docker-compose.yaml
services:

  not-baked-in:
    container_name: not-baked-in
    image: nodered/node-red:3.0.0-16-minimal
    volumes:
      - ./:/data/
    ports:
      - "1880:1880" # web ui

  baked-in-workdir:
    container_name: baked-in-workdir
    build:
      context: .
      dockerfile: Dockerfile.baked-in-workdir
    ports:
      - "1880:1880" # web ui

  baked-in-userdir:
    container_name: baked-in-userdir
    build:
      context: .
      dockerfile: Dockerfile.baked-in-userdir
    ports:
      - "1880:1880" # web ui
Dockerfile.baked-in-workdir
FROM nodered/node-red:3.0.0-16-minimal
RUN npm i \
        node-red-debugger@1.1.1 \
        pg@8.6.0 \
        --unsafe-perm --no-update-notifier --no-fund --omit=dev
Dockerfile.baked-in-userdir
FROM nodered/node-red:3.0.0-16-minimal
RUN cd /data/
COPY package.json flows.json settings.js ./
RUN npm i \
        --unsafe-perm --no-update-notifier --no-fund --omit=dev
package.json
{
    "name": "my-node-red",
    "version": "0.0.1",
    "dependencies": {
        "node-red-debugger": "1.1.1",
        "pg": "8.6.0"
    }
}
flows.json

[{"id":"0219bb93a4e9f932","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"c3aaf3a15f27e455","type":"inject","z":"0219bb93a4e9f932","name":"init","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":90,"y":60,"wires":[["a2c53a9c97709bfc"]]},{"id":"a2c53a9c97709bfc","type":"function","z":"0219bb93a4e9f932","name":"try pg lib","func":"let PgPool = pg.Pool;\nlet pool = new PgPool();\n\npool.query(\"SELECT 'Test' as [TestMsg]\", (err, res) => {\n if (err) {\n msg.result = err;\n }\n \n msg.result = res.rows[0];\n})\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"pg","module":"pg@8.6.0"}],"x":240,"y":60,"wires":[["6fbe3d1f1df9f9da"]]},{"id":"6fbe3d1f1df9f9da","type":"debug","z":"0219bb93a4e9f932","name":"dbg","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":60,"wires":[]}]

settings.js

As per original, except...

Outputs

not-baked-in

> docker compose up not-baked-in

TLDR/Results:
no pg/lib install
no error message
flow debug installed
flow stop feature enabled
baked-in/portable image
inject output in debug panel

Details:

not-baked-in  |
not-baked-in  | > node-red-docker@3.0.0 start
not-baked-in  | > node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS "--userDir" "/data"
not-baked-in  |
not-baked-in  | 18 Jul 22:00:11 - [info]
not-baked-in  |
not-baked-in  | Welcome to Node-RED
not-baked-in  | ===================
not-baked-in  |
not-baked-in  | 18 Jul 22:00:11 - [info] Node-RED version: v3.0.0
not-baked-in  | 18 Jul 22:00:11 - [info] Node.js  version: v16.16.0
not-baked-in  | 18 Jul 22:00:11 - [info] Linux 5.4.72-microsoft-standard-WSL2 x64 LE
not-baked-in  | 18 Jul 22:00:13 - [info] Loading palette nodes
not-baked-in  | 18 Jul 22:00:16 - [info] Settings file  : /data/settings.js
not-baked-in  | 18 Jul 22:00:16 - [info] Context store  : 'default' [module=memory]
not-baked-in  | 18 Jul 22:00:16 - [info] User directory : /data
not-baked-in  | 18 Jul 22:00:16 - [warn] Projects disabled : editorTheme.projects.enabled=false
not-baked-in  | 18 Jul 22:00:16 - [info] Flows file     : /data/flows.json
not-baked-in  | 18 Jul 22:00:16 - [info] Server now running at http://127.0.0.1:1880/
not-baked-in  | 18 Jul 22:00:16 - [warn]
not-baked-in  |
not-baked-in  | ---------------------------------------------------------------------
not-baked-in  | Your flow credentials file is encrypted using a system-generated key.
not-baked-in  |
not-baked-in  | If the system-generated key is lost for any reason, your credentials
not-baked-in  | file will not be recoverable, you will have to delete it and re-enter
not-baked-in  | your credentials.
not-baked-in  |
not-baked-in  | You should set your own key using the 'credentialSecret' option in
not-baked-in  | your settings file. Node-RED will then re-encrypt your credentials
not-baked-in  | file using your chosen key the next time you deploy a change.
not-baked-in  | ---------------------------------------------------------------------
not-baked-in  |
not-baked-in  | 18 Jul 22:00:16 - [warn] Encrypted credentials not found
not-baked-in  | 18 Jul 22:00:16 - [info] Starting flows
not-baked-in  | 18 Jul 22:00:16 - [error] [function:a2c53a9c97709bfc] Error: Cannot find module 'pg@8.6.0'
not-baked-in  | Require stack:
not-baked-in  | - /data/node_modules/pg@8.6.0
not-baked-in  | 18 Jul 22:00:16 - [info] Started flows

Cleanup: > docker compose down not-baked-in

baked-in-workdir

> docker compose up baked-in-workdir

TLDR/Results:
no pg/lib install
no error message
flow debug installed
flow stop feature enabled
baked-in/portable image
inject output in debug panel

Details:

baked-in-workdir  |
baked-in-workdir  | > node-red-docker@3.0.0 start
baked-in-workdir  | > node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS "--userDir" "/data"
baked-in-workdir  |
baked-in-workdir  | 18 Jul 22:44:38 - [info]
baked-in-workdir  |
baked-in-workdir  | Welcome to Node-RED
baked-in-workdir  | ===================
baked-in-workdir  |
baked-in-workdir  | 18 Jul 22:44:38 - [info] Node-RED version: v3.0.0
baked-in-workdir  | 18 Jul 22:44:38 - [info] Node.js  version: v16.16.0
baked-in-workdir  | 18 Jul 22:44:38 - [info] Linux 5.4.72-microsoft-standard-WSL2 x64 LE
baked-in-workdir  | 18 Jul 22:44:40 - [info] Loading palette nodes
baked-in-workdir  | 18 Jul 22:44:42 - [info] Settings file  : /data/settings.js
baked-in-workdir  | 18 Jul 22:44:42 - [info] Context store  : 'default' [module=memory]
baked-in-workdir  | 18 Jul 22:44:42 - [info] User directory : /data
baked-in-workdir  | 18 Jul 22:44:42 - [warn] Projects disabled : editorTheme.projects.enabled=false
baked-in-workdir  | 18 Jul 22:44:42 - [info] Flows file     : /data/flows.json
baked-in-workdir  | 18 Jul 22:44:42 - [warn]
baked-in-workdir  |
baked-in-workdir  | ---------------------------------------------------------------------
baked-in-workdir  | Your flow credentials file is encrypted using a system-generated key.
baked-in-workdir  |
baked-in-workdir  | If the system-generated key is lost for any reason, your credentials
baked-in-workdir  | file will not be recoverable, you will have to delete it and re-enter
baked-in-workdir  | your credentials.
baked-in-workdir  |
baked-in-workdir  | You should set your own key using the 'credentialSecret' option in
baked-in-workdir  | your settings file. Node-RED will then re-encrypt your credentials
baked-in-workdir  | file using your chosen key the next time you deploy a change.
baked-in-workdir  | ---------------------------------------------------------------------
baked-in-workdir  |
baked-in-workdir  | 18 Jul 22:44:42 - [info] Server now running at http://127.0.0.1:1880/
baked-in-workdir  | 18 Jul 22:44:42 - [warn] Encrypted credentials not found
baked-in-workdir  | 18 Jul 22:44:42 - [info] Installing module: pg, version: 8.6.0
baked-in-workdir  | 18 Jul 22:44:49 - [info] Installed module: pg@8.6.0
baked-in-workdir  | 18 Jul 22:44:49 - [info] Starting flows
baked-in-workdir  | 18 Jul 22:44:49 - [error] [function:a2c53a9c97709bfc] Error: Cannot find module 'pg@8.6.0'
baked-in-workdir  | Require stack:
baked-in-workdir  | - /data/node_modules/pg@8.6.0
baked-in-workdir  | 18 Jul 22:44:49 - [info] Started flows

Note: despite "installed" message, and lib being in both workDir and userDir, a "Cannot find" error is returned

> docker exec -it baked-in-workdir sh
~ $ pwd
/usr/src/node-red
~ $ npm ls --depth=0
node-red-docker@3.0.0 /usr/src/node-red
+-- node-red-debugger@1.1.1
+-- node-red@3.0.0
`-- pg@8.6.0

~ $ cd /data
/data $ npm ls --depth=0
node-red-project@0.0.1 /data
`-- pg@8.6.0

Cleanup: > docker compose down baked-in-workdir

baked-in-userdir

> docker compose up baked-in-userdir

TLDR/Results:
no pg/lib install
no error message
flow debug installed
flow stop feature enabled
baked-in/portable image
inject output in debug panel

Details:

aked-in-userdir  | npm ERR! Missing script: "start"
baked-in-userdir  | npm ERR!
baked-in-userdir  | npm ERR! Did you mean one of these?
baked-in-userdir  | npm ERR!     npm star # Mark your favorite packages
baked-in-userdir  | npm ERR!     npm stars # View packages marked as favorites
baked-in-userdir  | npm ERR!
baked-in-userdir  | npm ERR! To see a list of scripts, run:
baked-in-userdir  | npm ERR!   npm run
baked-in-userdir  |
baked-in-userdir  | npm ERR! A complete log of this run can be found in:
baked-in-userdir  | npm ERR!     /data/.npm/_logs/2022-07-18T22_55_00_980Z-debug-0.log
baked-in-userdir exited with code 1

Cleanup: > docker compose down baked-in-userdir

I imagine if I added node-red@3.0.0 to the package.json to the baked-in-userdir service, it would work... but then why use FROM nodered/node-red:3.0.0-16-minimal in dockerfile/etc? Changing functionExternalModules to false might prevent installation of packages, but it is unclear why it thinks it needs to install them to begin with?

What am I missing?

PS: functionExternalModules = false for baked-in-workdir gives...

19 Jul 02:01:31 - [error] [function:7313a330f49cc770] Error: Function node not allowed to load external modules

The warning I got from the system when I tried posting my first draft... :laughing:

image

Thank goodness I found the source for settings.js to link to

Using the docker-alpine.sh script, which puts the package.json in workDir and flows.json in userDir, and then docker run -it --rm -p 1880:1880 --name nr30 testing:node-red-build

no pg/lib install
no error message
flow debug installed
flow stop feature enabled
baked-in/portable image
inject output in debug panel

> docker exec -it nr30 sh does show that the packages matching the package.json expected are in the workDir/node_modules path. There are also the same (and a number more) packages in the userDir/node_modules path. Why does it install them again, what is the point of installing them via the package.json beforehand?

I did notice (which makes sense) that the package.json copied into the workDir must include the start script as per the docs.

With a minor adaptation I think I can use the example in getting-started/docker

Hmm... no luck with the getting-started guide, as follows...

Inputs

docker-compose.yaml
services:
  getting-started:
    container_name: getting-started
    build:
      context: .
      dockerfile: Dockerfile.getting-started
    ports:
      - "1880:1880"
Dockerfile.getting-started

Should closely resemble the example from docs. There was no discernible difference in error messages if file copies were CHOWNd or not (all it accomplishes currently is changes group from root to node-red for things copied in, vs unmodified).

FROM nodered/node-red:3.0.0-16-minimal
COPY --chown=node-red:node-red package.full.json ./package.json
RUN npm install --unsafe-perm --no-update-notifier --no-fund --omit=dev
COPY --chown=node-red:node-red flows.json settings.js /data/
package.full.json

Includes node-red itself (otherwise it gets removed during npm install), and the default start script

{
    "name": "node-red-project",
    "description": "A Node-RED Project",
    "version": "0.0.1",
    "private": true,
    "dependencies": {
        "node-red": "3.0.0",
        "node-red-debugger": "1.1.1",
        "pg": "8.6.0"
    },
    "scripts": {
        "start": "node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS"
    }
}
flows.json

[{"id":"0219bb93a4e9f932","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"c3aaf3a15f27e455","type":"inject","z":"0219bb93a4e9f932","name":"init","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":90,"y":60,"wires":[["a2c53a9c97709bfc"]]},{"id":"a2c53a9c97709bfc","type":"function","z":"0219bb93a4e9f932","name":"try pg lib","func":"try {\nlet PgPool = pg.Pool;\nlet pool = new PgPool();\n\npool.query(\"SELECT 'Test' as [TestMsg]\", (err, res) => {\n if (err) {\n msg.result = err;\n }\n \n msg.result = res.rows[0];\n})\n} catch (ex) {\n return msg.ex = ex;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"pg","module":"pg@8.6.0"}],"x":240,"y":60,"wires":[["6fbe3d1f1df9f9da"]]},{"id":"6fbe3d1f1df9f9da","type":"debug","z":"0219bb93a4e9f932","name":"dbg","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":60,"wires":[]}]

settings.js

As per original , except...

Outputs

TLDR/Results:
no pg/lib install
no error message
flow debug installed
flow stop feature enabled
baked-in/portable image
inject output in debug panel

Details:

docker compose up getting-started

log

getting-started |
getting-started | > node-red-project@0.0.1 start
getting-started | > node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS "--userDir" "/data"
getting-started |
getting-started | 24 Jul 03:47:00 - [info]
getting-started |
getting-started | Welcome to Node-RED
getting-started | ===================
getting-started |
getting-started | 24 Jul 03:47:00 - [info] Node-RED version: v3.0.0
getting-started | 24 Jul 03:47:00 - [info] Node.js version: v16.16.0
getting-started | 24 Jul 03:47:00 - [info] Linux 5.4.72-microsoft-standard-WSL2 x64 LE
getting-started | 24 Jul 03:47:02 - [info] Loading palette nodes
getting-started | 24 Jul 03:47:04 - [info] Settings file : /data/settings.js
getting-started | 24 Jul 03:47:04 - [info] Context store : 'default' [module=memory]
getting-started | 24 Jul 03:47:04 - [info] User directory : /data
getting-started | 24 Jul 03:47:04 - [warn] Projects disabled : editorTheme.projects.enabled=false
getting-started | 24 Jul 03:47:04 - [info] Flows file : /data/flows.json
getting-started | 24 Jul 03:47:05 - [warn]
getting-started |
getting-started | ---------------------------------------------------------------------
getting-started | Your flow credentials file is encrypted using a system-generated key.
getting-started |
getting-started | If the system-generated key is lost for any reason, your credentials
getting-started | file will not be recoverable, you will have to delete it and re-enter
getting-started | your credentials.
getting-started |
getting-started | You should set your own key using the 'credentialSecret' option in
getting-started | your settings file. Node-RED will then re-encrypt your credentials
getting-started | file using your chosen key the next time you deploy a change.
getting-started | ---------------------------------------------------------------------
getting-started |
getting-started | 24 Jul 03:47:05 - [info] Server now running at http://127.0.0.1:1880/
getting-started | 24 Jul 03:47:05 - [warn] Encrypted credentials not found
getting-started | 24 Jul 03:47:05 - [info] Installing module: pg, version: 8.6.0
getting-started | 24 Jul 03:47:11 - [info] Installed module: pg@8.6.0
getting-started | 24 Jul 03:47:11 - [info] Starting flows
getting-started | 24 Jul 03:47:11 - [error] [function:a2c53a9c97709bfc] Error: Cannot find module 'pg@8.6.0'
getting-started | Require stack:
getting-started | - /data/node_modules/pg@8.6.0
getting-started | 24 Jul 03:47:11 - [info] Started flows

Maybe at this point a bug report of some sort would be appropriate?

I have to start by saying that my docker skills are not so advanced like what you are trying to do.
As a workaround try using the functionGlobalContext instead

 functionGlobalContext: {
         pg:require('pg'),
    },

and set functionExternalModules: false, in your settings.js (as you had at some point)

also re-adjust your flow to not use functionExternalModules but let pg = global.get("pg")

flow.json
[
    {
        "id": "c3aaf3a15f27e455",
        "type": "inject",
        "z": "0defad76537bdd90",
        "name": "init",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 370,
        "y": 120,
        "wires": [
            [
                "a2c53a9c97709bfc"
            ]
        ]
    },
    {
        "id": "a2c53a9c97709bfc",
        "type": "function",
        "z": "0defad76537bdd90",
        "name": "try pg lib",
        "func": "let pg = global.get(\"pg\")\nnode.warn(pg)\n\n// try {\n// let PgPool = pg.Pool;\n// let pool = new PgPool();\n\n// pool.query(\"SELECT 'Test' as [TestMsg]\", (err, res) => {\n//  if (err) {\n//  msg.result = err;\n//  }\n \n//  msg.result = res.rows[0];\n// })\n// } catch (ex) {\n//  return msg.ex = ex;\n// }",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 520,
        "y": 120,
        "wires": [
            [
                "6fbe3d1f1df9f9da"
            ]
        ]
    },
    {
        "id": "6fbe3d1f1df9f9da",
        "type": "debug",
        "z": "0defad76537bdd90",
        "name": "dbg",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 710,
        "y": 120,
        "wires": []
    }
]

Thank you so much!

I thought with the newer versions of Node-RED the functionGlobalContext was deprecated (or marked for it?)... but reverting settings.js, functionExternalModules and functionGlobalContext certainly addressed the libraries being installed and the error message about being unable to find them anyway.

I am still getting some unexpected behavior, but I think it is related to my current use/config of the Postgres client library (`pg'). I'll keep poking.

Updated flows.json...

[{"id":"0219bb93a4e9f932","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"c3aaf3a15f27e455","type":"inject","z":"0219bb93a4e9f932","name":"init","props":[{"p":"ts","v":"","vt":"date"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":90,"y":60,"wires":[["a2c53a9c97709bfc"]]},{"id":"a2c53a9c97709bfc","type":"function","z":"0219bb93a4e9f932","name":"try pg lib","func":"try {\n    let pg = global.get(\"pg\");\n    let PgPool = pg.Pool;\n    let pool = new PgPool();\n    msg.pool = pool; // debug\n\n    pool.query(\"SELECT 'Test' as [TestMsg]\", (err, res) => {\n        if (err) {\n            msg.result = err;\n        } else {\n            msg.result = res;\n        }\n    })\n} catch (ex) {\n    msg.ex = ex;\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":240,"y":60,"wires":[["6fbe3d1f1df9f9da"]]},{"id":"6fbe3d1f1df9f9da","type":"debug","z":"0219bb93a4e9f932","name":"dbg","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":60,"wires":[]}]

cool .. im glad it worked

yea .. i noticed some errors too when running the Function with pg library .. but the main thing is that it loads.

Why dont you pre-install a postgres node instead of using the pg library ? .. we are in Nodered after all :wink:

An excellent question :grinning: ...I evaluated the options once upon a time, and I dont recall now what the reasoning was for going this route (some feature gap at the time, IIRC). I'll look into it again.

FWIW, the winning combo for me was...

  • FROM nodered/node-red:3.0.1-16-minimal
  • copy a package.json that included a dependency for node-red itself (and debugger) in the workDir ('/usr/src/node-red), and run npm install` from there.
  • package.json (in workDir) and flows.json and settings.js (in userDir, aka: /data/) "baked in"
  • externalModules default/commented-out
  • functionExternalModules false
  • added one lib to functionGlobalContext
  • runtimeState enabled
  • created my own /organization/settings (with proper permissions) for the data I do need to volume map into and read from in my flows (from a known location). this way it doesnt interfere with the expected contents of /data