# Command-line render

> Render .oink and .nk scripts from a terminal or a render farm with standard render flags, progress lines and exit codes.

`render.sh` (Windows: `render.bat`) in the install folder renders a script with no window and no display. It takes the standard command-line render flags and prints the usual progress lines, so a render-farm plugin written for `nuke -x` can call it instead.

```
./render.sh -x -F 1-100 -X Write1 shot.nk
./render.sh -F 1001-1100x5 --cont -m 8 comp.oink
./render.sh --cpu -F 1 comp.oink          # no GPU: software rendering
```

## Flags

| Flag | What it does |
|---|---|
| `<script>` | a `.oink` or `.nk` script (an `.nk` is imported first) |
| `-x` | render. Accepted so existing farm scripts work; rendering is the default |
| `-F <range>` | frames: `1-100`, `1-100x5` (every 5th), `1,5,10`. Repeat `-F` for more ranges. Default: the script's frame range |
| `-X <Write>` | render only this Write node. Repeat it (or use `Write1,Write2`) for several. Default: every enabled Write, in render order |
| `-m <n>` | number of threads |
| `--cont` | keep going after a frame fails |
| `-f` | full size (the default) |
| `-p` | proxy: not supported yet (Write nodes have no proxy file path); exits with code 2 |
| `-V [level]` | more output: `1` script loading and the checks, `2` everything, including the engine's own messages |
| `-q` | quiet: only the progress lines and errors |
| `--view <name>` | views to render; scripts have one view, `main` |
| `-i` | accepted and ignored (there is no interactive licence) |
| `--gpu [N]`, `--gpu-index N` | render on GPU number N (also sets `CUDA_VISIBLE_DEVICES=N`) |
| `--cpu` | render with no GPU, on Mesa's software Vulkan driver (lavapipe). Same pixels, slower |
| `--require-gpu` | fail with exit code 3 if the machine has no working GPU and the engine fell back to a software renderer |
| `--renderer any\|gpu\|cpu` | the same choice as one flag, for farm templates: `gpu` = `--require-gpu`, `cpu` = `--cpu` |
| `--json` | also print machine-readable `OCBG {...}` event lines |
| `--no-verify` | skip reading each written file back |
| `--openjd` | also print Open Job Description progress lines, which AWS Deadline Cloud shows as task progress |
| `--path-map <file>` | remap file paths in the script (Read, Write...) with Open Job Description path-mapping rules (JSON) |
| `--list-writes` | print the script's Write nodes as JSON (name, enabled, order, output path, frame range, dependencies) and exit; for farm submitters |
| `--localize` | read the local copies made by Localization (when they match their source by size and time) instead of the network files. `--use-local-file-cache` works too |
| `--worker` | run this machine as a LAN render-farm worker (see [LAN render farm](/docs/nuke-users/lan-render-farm)) |
| `--collect <script> <dest>` | copy the comp and every file it uses into a folder (like File > Collect Files). Options: `--all-frames`, `--proxies`, `--ai-caches`, `--no-ocio`, `--zip` |
| `--prep-show <edl, otio, folder or json> --out <dir>` | analyse every shot of a show (see [Prep Show](/docs/concepts/prep-show)). Options: `--shots`, `--chunk i/n`, `--merge-only` |
| `--diag-bundle [--out F.zip]` | write a redacted diagnostic zip (see [Logs and diagnostics](/docs/logs-diagnostics)) |
| `--mcp-setup [claude-code\|claude-desktop]` | connect Claude Code or Claude Desktop to the running app's MCP server |
| `--version` | print the version |

Other flags a farm may pass (`--nukex`, `--priority`, `-c`, …) are accepted and ignored.

## Output

The first line says what it renders on, so a farm log shows at once when a machine lost its GPU:

```
Renderer: GPU, NVIDIA GeForce RTX 4090/PCIe/SSE2 (OPENGL, NVIDIA Corporation)
Renderer: CPU (software: llvmpipe), llvmpipe (LLVM 20.1.8, 256 bits) (OPENGL, Mesa)
```

On a software renderer that you did not ask for (`--cpu`) it also prints `WARNING: no GPU: ...`. Add `--require-gpu` to make that an error instead (exit code 3). The pixels are the same either way: a CPU render matches the GPU one to within float rounding.

For each frame it prints the same lines Nuke does:

```
Frame 1001 (1 of 100)
Writing /shots/sh010/comp/sh010_comp.1001.exr took 0.42 seconds
...
Total render time: 43.18 seconds
```

Each frame is also checked for NaN or infinite pixels and for an all-black frame. A flagged frame is still written, and a line like `WARNING: Write1: frame 1004: black frame (every RGB value is 0)` is printed.

Errors start with `ERROR:`, for example `ERROR: Write1: frame 1004: bad output ... (file removed)`.

## Checks before and after rendering

Before the first frame it stops, listing every problem at once, when:

- input files are missing (the list shows each missing file and the Read node that needs it);
- an OFX plugin or a gizmo the script uses is not installed;
- an output folder does not exist (unless the Write has **create directories** on) or cannot be written to;
- there is no usable GPU (use `--gpu-index` to pick another one, or `--cpu`).

Image frames are written to a hidden temporary file in the same folder and renamed when complete, so nothing sees a half-written frame. After each file is written it is read back: it must exist, be larger than zero bytes, open, have every pixel readable, and have the expected resolution and channels. A partial or broken file counts as a failed frame and is deleted.

## Exit codes

| Code | Meaning |
|---|---|
| 0 | every frame written and checked |
| 1 | a frame failed, or the script could not be loaded, or the preflight check failed |
| 2 | bad command line |
| 3 | no usable GPU (or, with `--require-gpu`, only a software renderer) |
| 130 / 143 | stopped by Ctrl-C / SIGTERM |

## Stopping a render

The first SIGTERM or Ctrl-C lets the frame being rendered finish, then stops. A second one aborts that frame and deletes its partial file. With `--cont`, frames that fail are skipped and the exit code is still 1.

## On a render farm

- Point the farm's Nuke executable at `render.sh` (or `render.bat`) and keep its usual Nuke command line.
- Every GPU render takes the machine's GPU lease, so one GPU job runs at a time on a machine: a second render (or an AI job) waits for the first. Renders with `--cpu` do not need the lease.
- A machine with no GPU can render with `--cpu`.


---
Sources: render.sh, render.bat, opencomp_server/render_cli.py, opencomp_server/render_cli_worker.py
