Deploy a Node.js service
An Express service with configuration injected from a configmap — change config without rebuilding the image.
This recipe deploys a minimal Express service whose configuration comes from a Rune configmap via envFrom. The image stays generic; the environment owns the config.
Full source: runestack/rune-examples/node-express.
The app
One endpoint that reads its greeting from the environment, plus a health endpoint:
import express from 'express'
import os from 'node:os'
const app = express()
// GREETING comes from a Rune configmap via envFrom (see deploy/app.yaml).
const greeting = process.env.GREETING ?? 'hello from node on rune'
app.get('/api/hello', (req, res) => {
res.json({ message: greeting, instance: os.hostname() })
})
app.get('/healthz', (req, res) => {
res.send('ok')
})
app.listen(process.env.PORT ?? 3000)
The spec
Two resources in one castfile: the configmap and the service that consumes it. envFrom turns every key in the configmap into an environment variable, and the dependency makes the rollout wait until the configmap exists:
---
configmap:
name: node-hello-settings
namespace: demo
data:
GREETING: hello from node on rune
---
service:
name: node-hello
namespace: demo
image: node-hello:dev
scale: 2
ports:
- name: http
port: 3000
dependencies:
- configmap:node-hello-settings
envFrom:
- configmap: node-hello-settings
health:
liveness:
type: http
path: /healthz
port: 3000
initialDelaySeconds: 2
intervalSeconds: 10
expose:
port: http
host: node-hello.local
Cast it
git clone https://github.com/runestack/rune-examples
cd rune-examples/node-express
docker build -t node-hello:dev ./app
rune lint deploy/app.yaml
rune cast deploy/app.yaml
echo "127.0.0.1 node-hello.local" | sudo tee -a /etc/hosts
curl http://node-hello.local/api/hello
# {"message":"hello from node on rune","instance":"87f68dc74039"}
In dev mode the ingress binds :8080, so use http://node-hello.local:8080.
Change config without rebuilding
Update the configmap and roll the service — the new value arrives as an env var on the next instance start. No image rebuild, no spec change:
rune create config node-hello-settings -n demo \
--from-literal=GREETING="howdy from a configmap"
rune restart node-hello -n demo
curl http://node-hello.local/api/hello
# {"message":"howdy from a configmap","instance":"3c9d01ab54e2"}
Rune does not hot-reload env vars or mounted files — the restart is what picks up the new version. See Secrets & ConfigMaps.
rune delete -f deploy/app.yaml # tear down
Adapting
Anything that reads config from the environment — which is to say, any twelve-factor app — works the same way: FastAPI, Rails, Spring. For sensitive values, use a secret instead of a configmap; the service side is the same shape (envFrom: - secret: name). For a full stack with a database and secrets, see Deploy Spring Boot + React.