Docs / Deploying

Deploying

Send us your code as a zip or a git branch; we build it, start it and switch traffic over when it answers.

Zip or git

  • Zip: up to 50 MB. A zip with one folder at the top, as GitHub's “Download ZIP” makes, works too: we use that folder. Leave out node_modules, venv, vendor, bin/obj and target; we install and build inside.
  • Git: an https:// URL and a branch. Public repositories need nothing else; for a private one add a read-only deploy token, which we keep encrypted and never show in logs. We fetch only the latest commit of that branch.

How we read your project

We look at the files at the top of the project, in this order, and the first match decides the runtime:

If the top folder hasRuntime
a .csproj file.NET
pom.xml, build.gradle, build.gradle.kts or a .jarJava
requirements.txt or pyproject.tomlPython
composer.json or .php filesPHP
index.htmlStatic site

So a PHP app with an index.html is still PHP, and a Python project that also has a pom.xml builds as Java. You can also pick the runtime when you create the app.

Start command

Python and PHP apps can say how they start. We use the first of these we find:

  1. systemi.toml at the top of the project:
    start = "gunicorn mysite.wsgi -b 0.0.0.0:$PORT --workers 2"
    health = "/healthz"   # optional, see below
  2. A Procfile with a web: line, as other hosts use:
    web: uvicorn main:app --host 0.0.0.0 --port $PORT
  3. Our default for the runtime (each language guide lists it).

Java and .NET apps always start from the jar or the published project, so they need no start command.

Listen on PORT

Every app gets a PORT environment variable and must accept HTTP on that port on all addresses (0.0.0.0, not 127.0.0.1). We handle HTTPS in front of your app, so your app speaks plain HTTP. Requests arrive with the original Host header and the usual X-Real-IP, X-Forwarded-For and X-Forwarded-Proto headers. WebSockets work. A request should get its answer within 60 seconds; longer work belongs in a background job that the page checks on.

Health check

After a build we start the new version and call it on / (or the health path in systemi.toml). Any answer below 500 counts, so a redirect or a 404 is fine. If the app doesn't answer within a minute, the deploy fails and the version that was live keeps serving. A health path that skips the database and slow work makes deploys and wake-ups quicker.

Files at run time

  • Your app's files are read-only while it runs. Settings belong in environment variables, data in your database.
  • /tmp is writable for scratch files and small caches. It is emptied when the app restarts, sleeps or is redeployed, and what you keep there counts towards the app's memory.
  • Your app can reach the internet (APIs, payment providers, email services) and its own database.

Redeploys

Upload a new zip or press Deploy to fetch the branch again. The live version keeps serving while the new one builds; traffic moves over once the new version passes its health check. Changing environment variables only restarts the app, without a new build.

Logs and failed builds

The app page shows the build log of each deploy and the recent output of your running app (what it prints to stdout and stderr). Common build failures:

MessageWhat to do
no start commandadd systemi.toml with start = "..." or a Procfile web: line
the app did not answer on $PORT in timelisten on $PORT and 0.0.0.0; check the app log for a crash at start
build took longer than 10 minutestrim dependencies, or deploy a prebuilt jar or publish output
git clone failedcheck the URL, branch and deploy token
unsafe path in zipthe zip has absolute paths, .. or links; zip the folder again normally