Running Node.js

There is no separate Node preset class — you run JavaScript/Node with the same Machine API as everything else. Use run(image, command) to execute Node in a container image, or writeFile a script and run it. TypeScript is async; Python is synchronous.

Run JavaScript code

Use run with an inline node -e command against a Node image:

import { Machine } from 'smolmachines';

const machine = await Machine.create({ name: 'node-env' });
try {
  const result = await machine.run(
    'node:22-alpine',
    ['node', '-e', 'console.log("Node", process.version); console.log(2 + 3)']
  );
  console.log(result.stdout);
} finally {
  await machine.delete();
}
from smol import Machine, MachineConfig

with Machine.create(MachineConfig(name="node-env")) as machine:
    result = machine.run(
        "node:22-alpine",
        ["node", "-e", 'console.log("Node", process.version); console.log(2 + 3)'],
    )
    print(result.stdout)

Run a script file

Write the script into the machine with writeFile / write_file, then run it:

const machine = await Machine.create({ name: 'node-script' });
try {
  await machine.writeFile('/workspace/main.js', `
const data = { users: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }] };
const withEmail = data.users.map(u => ({
  ...u,
  email: \`\${u.name.toLowerCase()}@example.com\`,
}));
console.log(JSON.stringify(withEmail, null, 2));
`);

  const result = await machine.run('node:22-alpine', ['node', '/workspace/main.js']);
  console.log(JSON.parse(result.stdout));
} finally {
  await machine.delete();
}
with Machine.create(MachineConfig(name="node-script")) as machine:
    machine.write_file("/workspace/main.js", """
const data = { message: "Hello from Node.js!" };
console.log(JSON.stringify(data, null, 2));
""")

    result = machine.run("node:22-alpine", ["node", "/workspace/main.js"])
    print(result.stdout)

ES modules

Node treats .mjs files (or a package.json with "type": "module") as ES modules — write the file with an .mjs extension:

await machine.writeFile('/workspace/app.mjs', `
const add = (a, b) => a + b;
console.log('2 + 3 =', add(2, 3));
`);

const result = await machine.run('node:22-alpine', ['node', '/workspace/app.mjs']);
console.log(result.stdout);

Installing packages

Install with npm in the same container, then run your code — chain both in one run via sh -c:

const result = await machine.run('node:22-alpine', [
  'sh', '-c',
  'cd /workspace && npm install --silent lodash && node -e "console.log(require(\'lodash\').chunk([1,2,3,4,5], 2))"'
]);
console.log(result.stdout);

To watch a long install live, use execStream / exec_stream:

for await (const ev of machine.execStream(['npm', 'install', 'express'], { workdir: '/workspace' })) {
  if (ev.kind === 'stdout' || ev.kind === 'stderr') process.stdout.write(ev.data);
}

HTTP server example

Publish a port at create time, then start a server. On the cloud target, url() returns the public ingress URL.

const machine = await Machine.create({
  name: 'http-server',
  ports: [{ host: 3000, guest: 3000 }]
});

await machine.writeFile('/workspace/server.js', `
const http = require('http');
http.createServer((req, res) => {
  res.setHeader('content-type', 'application/json');
  res.end(JSON.stringify({ message: 'Hello from the machine!' }));
}).listen(3000, () => console.log('listening on 3000'));
`);

// Start the server (fire-and-forget; it keeps running in the machine)
machine.exec(['node', '/workspace/server.js']);

Working with files

Mount host directories and process files with the Node standard library:

const machine = await Machine.create({
  name: 'file-processor',
  mounts: [
    { source: '/data/input', target: '/input', readonly: true },
    { source: '/data/output', target: '/output' }
  ]
});

try {
  await machine.writeFile('/workspace/process.js', `
const fs = require('fs');
const path = require('path');
for (const file of fs.readdirSync('/input')) {
  const content = fs.readFileSync(path.join('/input', file), 'utf8');
  fs.writeFileSync(path.join('/output', file), content.toUpperCase());
}
console.log('Processing complete!');
`);

  const result = await machine.run('node:22-alpine', ['node', '/workspace/process.js']);
  console.log(result.stdout);
} finally {
  await machine.delete();
}