Node.js Runtime

Host Node.js applications on Witchly.host. Deploy from Git, install npm packages, and run any index.js-style entrypoint with dedicated resources.

Node.js Runtime

The Node.js egg runs Node.js 25.x via the ghcr.io/ptero-eggs/yolks:nodejs_25 image. Clone a Git repo on install, install dependencies, run any JavaScript or TypeScript-compiled-to-JS entrypoint.

Quick deploy

  1. dash.witchly.hostDeployLanguagesNode.js.
  2. On the Startup tab, set:
    • Git Repo Address — e.g. https://github.com/you/your-bot.git
    • Main file — the entrypoint path (default index.js)
    • Additional Node packages — space-separated npm package names (optional, installed on startup)
  3. Start from the Console tab.

Startup flow

The egg runs this on each start:

# Pull latest if AUTO_UPDATE=1
if [[ -d .git ]] && [[ {{AUTO_UPDATE}} == "1" ]]; then git pull; fi

# Install any extra packages
if [[ ! -z ${NODE_PACKAGES} ]]; then /usr/local/bin/npm install ${NODE_PACKAGES}; fi

# Run your entrypoint
/usr/local/bin/node ${MAIN_FILE} ${NODE_ARGS}

Variables reference

VariablePurpose
GIT_ADDRESSGit repo URL. Leave blank to upload manually.
BRANCHGit branch/tag. Blank → repo default (usually main).
USER_UPLOAD1 to skip auto-clone; you upload via SFTP instead.
AUTO_UPDATE1 to git pull on every start.
MAIN_FILEEntrypoint (default index.js).
NODE_PACKAGESExtra npm packages to install on each boot.
UNNODE_PACKAGESPackages to uninstall on each boot (useful during testing).
NODE_ARGSFlags passed to Node (e.g., --max-old-space-size=512).
USERNAME, ACCESS_TOKENFor cloning private repos via HTTPS.

Private repos

Create a GitHub/GitLab personal access token with read-only repo scope, then fill:

  • USERNAME — your Git username
  • ACCESS_TOKEN — the token

The egg clones with https://USERNAME:ACCESS_TOKEN@host/path.git under the hood.

Environment variables (your app’s)

Any process.env.* variable your app needs can be set on the Startup tab by adding custom variables — edit via the Pterodactyl Variables area, or just use a .env file in your repo and load it with dotenv:

import "dotenv/config"
console.log(process.env.DISCORD_TOKEN)

Installing dependencies

The egg automatically runs npm install on install (one time) and re-runs it if NODE_PACKAGES is set. To install packages manually:

  1. On the Console tab, type: npm install <package>
  2. Or via the Files tab, edit package.json and restart — dependencies install on boot.

TypeScript

Two options:

Option A — build before deploy. Compile locally (tsc) and commit dist/ to your repo. Set MAIN_FILE=dist/index.js.

Option B — run TS directly. Add tsx or ts-node as a dependency, then override the startup to npx tsx src/index.ts. (Requires editing the startup command — ask support if the default egg constrains this.)

Logs & the console

console.log and console.error stream to the Pterodactyl console in real time. The console is also a stdin — you can type into your app if it reads from process.stdin.

Memory tuning

Node’s default heap is ~512 MB regardless of your server’s RAM. On plans with >1 GB RAM, increase it:

NODE_ARGS = --max-old-space-size=1536

(1.5 GB = 1536 MB; adjust for your plan.)

Troubleshooting

  • “Cannot find module ‘foo’” — add foo to package.json and restart, or set NODE_PACKAGES=foo.
  • Crashes with no output — check memory; if node exits with FATAL ERROR: Ineffective mark-compacts..., raise --max-old-space-size or upgrade.
  • Git clone fails — private repo needs USERNAME+ACCESS_TOKEN, or the .git URL is wrong.

Next steps