Help Center

Deploying

Language guides and static sites

What Nixpacks detects for Node.js, Python, Go, PHP, Ruby and Java, how to set start commands and versions, and how to host static sites and SPAs.

With the Nixpacks build type (the default), MarvX runs Nixpacks on your repository root to detect the language, install dependencies, build and pick a start command. A root Dockerfile takes precedence.

Rules for every language

  1. Listen on 0.0.0.0 and the PORT variable (MarvX sets PORT=3000 unless you set it).
  2. Make the start command explicit with a Procfile (web: <command>) or nixpacks.toml.
  3. Commit your lockfile.
  4. Project environment variables exist only at runtime, not during the build. Put build settings in nixpacks.toml (it's committed, so no secrets).
  5. The app must be at the repository root (see Dockerfiles, images and Compose for monorepos).
# nixpacks.toml (repository root)
[variables]
NODE_ENV = "production"

[phases.build]
cmds = ["npm run build"]

[start]
cmd = "node dist/server.js"

Node.js

  • Detected by package.json. The package manager follows the lockfile: npm, Yarn, pnpm or Bun. Installs are frozen, so a stale lockfile fails the build.
  • Runs the build script if present, then the start script.
  • Version: "engines": { "node": "20" } or .nvmrc.
  • NEXT_PUBLIC_* / VITE_* values must be known at build time: set non-secret ones in nixpacks.toml [variables], or build with a Dockerfile.
app.listen(process.env.PORT || 3000, "0.0.0.0");

Python

  • Detected by requirements.txt, pyproject.toml (incl. Poetry) or Pipfile. Version: .python-version.
  • Start command in a Procfile, e.g. web: gunicorn myproject.wsgi --bind 0.0.0.0:$PORT or web: uvicorn main:app --host 0.0.0.0 --port $PORT. Add the server package to your dependencies.

Go

  • Detected by go.mod (which sets the Go version). Nixpacks builds and runs the binary.
  • If main isn't at the root, set build and start commands in nixpacks.toml. Listen on ":" + os.Getenv("PORT").

PHP

  • Detected by composer.json (Laravel by artisan). Served by nginx and PHP-FPM on PORT.
  • Set APP_KEY and other settings as variables; run migrations from Open Terminal or a cron schedule.

Ruby

  • Detected by Gemfile (Rails automatically). Version: .ruby-version or Gemfile.
  • web: bundle exec rails server -b 0.0.0.0 -p $PORT, and set SECRET_KEY_BASE or RAILS_MASTER_KEY.

Java

  • Detected by pom.xml or build.gradle(.kts); commit the Maven or Gradle wrapper.
  • Read PORT (Spring Boot: server.port=${PORT:3000}). Override the start command in nixpacks.toml if needed, e.g. cmd = "java -jar target/app.jar".
  • Keep the heap under your plan's memory cap, e.g. JAVA_TOOL_OPTIONS=-Xmx384m on Free.

Static sites

The Static site (nginx) build type serves files with nginx and doesn't run a build command. It serves the first folder that exists: dist, build, public, out, otherwise the repository root. Unknown paths fall back to index.html, so single-page-app routing works.

  1. Commit the files to serve (e.g. a built dist/).
  2. Build Type: Static site (nginx), Save, then Deploy.

Don't set PORT on a static site: nginx listens on 3000 and a different PORT breaks routing.

For sites that need building (Vite, Astro, CRA…): commit the build output, or use Nixpacks with a start script that serves the output on $PORT (e.g. npx serve -s dist -l $PORT), or a multi-stage Dockerfile.

When detection fails

The language files aren't at the root or the language isn't supported. Add a Dockerfile and choose Dockerfile. See Troubleshooting builds and deployments.