All posts

marina.toml: tell Marina how to build and run your app

· Marina

When you deploy from GitHub, Marina detects your stack and figures out how to build and start your app. Most projects never need more than that. When you do want to be explicit, you add one small file to the root of your repo: marina.toml. This post walks through everything it can do.

The shape of the file

marina.toml is optional. When it exists, it is the source of truth. A complete file looks like this:

[build]
# command    = "npm run build"
# dockerfile = "docker/Dockerfile"

[build.env]
# VITE_API_URL = "https://api.example.com"

[processes]
# web = "node server.js"

Every key is optional too. You only write the parts you want to control.

Declare your start command

If your app builds fine but does not start, or starts the wrong thing, declare the command yourself:

[processes]
web = "node server.js"

web is the process that serves HTTP traffic. With it declared, there is no guessing: your app starts exactly how you said it should, every deploy.

Build-time variables

This is the one most people come for. Frameworks like Vite, Create React App, and Next.js bake certain variables into your code at build time. A variable like VITE_SUPABASE_URL has to exist while npm run build runs, or the build fails or ships an app pointing at nothing.

Declare them in [build.env]:

[build.env]
VITE_SUPABASE_URL = "https://xyz.supabase.co"
VITE_SUPABASE_ANON_KEY = "eyJhbGciOi..."

Push, and your next deploy builds with them in place.

Two rules keep this safe:

  • These are build-time only. Your running app gets the environment variables you set in the dashboard, not these. The two lists do different jobs: the dashboard holds what your server reads while running, [build.env] holds what your build bakes in.
  • Never put real secrets here. marina.toml is committed to your repo, so anything in it is as visible as your code. That is fine for the values above (a Vite variable ends up readable in your shipped JavaScript anyway), but a database password or a private API key belongs in the dashboard, never in a committed file.

Values must be quoted strings, up to 32 variables, 1024 characters each.

If you build with a Dockerfile

A Dockerfile at the root of your repo is used automatically. marina.toml lets you adjust that:

[build]
dockerfile = "docker/Dockerfile.prod"

[build.env] works here too: each variable arrives as a build argument, so declare a matching ARG in your Dockerfile to use it:

ARG VITE_API_URL
RUN npm run build

No Dockerfile and no framework we recognize? build.command overrides the build step directly:

[build]
command = "npm run build:production"

Mistakes fail loudly

An invalid marina.toml never ships a broken app quietly. If a value is not a quoted string, a variable name is invalid, or a command is declared but empty, the deploy stops and tells you exactly what to fix.

Quick reference

KeyWhat it does
processes.webThe command that starts your app
build.envVariables present while your app builds
build.commandOverride the detected build command
build.dockerfileUse a Dockerfile at a custom path

Commit the file, push, and the next deploy picks it up. That is the whole workflow: no dashboard visit, no redeploy button, just a file in your repo that says what you mean.

Deploy something tonight