Skip to content

Bring An Existing Gleam App

This tutorial is for an existing Gleam HTTP app that already runs locally. It helps you check whether the app fits BeamUp SLC v1 and make the small changes needed for the supported deploy path.

BeamUp does not require a BeamUp SDK for basic deploy. The app contract is:

  • Erlang-targeted Gleam.
  • Exportable with gleam export erlang-shipment.
  • Direct argv start command.
  • Runtime-provided PORT.
  • HTTP bind on 0.0.0.0:<PORT>.
  • Path-only health check returning HTTP 2xx.

From the app directory, check that gleam.toml exists:

Terminal window
ls gleam.toml

If your deployable app is inside a subdirectory, remember that path. You can set it later as app_root in beamup.toml.

Open gleam.toml and check the target.

Supported:

target = "erlang"

Also supported: no target field, because Gleam defaults to Erlang.

Not supported in SLC v1:

target = "javascript"

BeamUp SLC v1 does not support JavaScript-targeted Gleam, Cloudflare Worker-targeted Gleam, Lustre/full-stack hosting, Elixir/Phoenix apps, or non-Gleam Erlang apps.

Run:

Terminal window
gleam export erlang-shipment

The usual BeamUp start command expects the exported entrypoint:

Terminal window
./build/erlang-shipment/entrypoint.sh run

If your app needs a different command, it must still be expressible as an argv array in beamup.toml. BeamUp does not run a shell string for start.

Your app must read the PORT environment variable at startup and bind HTTP traffic to that port.

A local check should look like this:

Terminal window
PORT=8000 ./build/erlang-shipment/entrypoint.sh run

Then in another terminal:

Terminal window
curl -i http://127.0.0.1:8000/

The deployed app must bind on 0.0.0.0:<PORT>, not only 127.0.0.1:<PORT>. Binding only to loopback can work locally but fail in the managed runtime.

Pick a path such as /healthz.

The health handler should:

  • Return HTTP 2xx when the process is ready for traffic.
  • Avoid dependency checks that make every external service hiccup look like app startup failure.
  • Avoid secrets, env values, request headers, cookies, or debug internals.
  • Be stable enough for deploy activation.

Check it locally:

Terminal window
curl -i http://127.0.0.1:8000/healthz

Run:

Terminal window
beamup init

Review the generated file:

app = "hello-gleam"
runtime = "erlang"
app_root = "."
start = ["./build/erlang-shipment/entrypoint.sh", "run"]
health = "/healthz"
[build]
target = "erlang"
env = "prod"
[deploy]
strategy = "blue_green"

If your app lives in a subdirectory, set app_root to that relative directory:

app_root = "services/web"

app_root must stay inside the project and point to a directory containing gleam.toml.

Do not add secrets or runtime env values to beamup.toml.

Invalid:

[secrets]
DATABASE_URL = "<database-url>"

Use BeamUp runtime configuration instead:

Terminal window
beamup --app hello-gleam env set FEATURE_FLAG=enabled
beamup --app hello-gleam env set DATABASE_URL=<database-url> --secret

Configuration changes apply to future runtime starts. Redeploy after setting a value that the app needs at startup.

BeamUp packages your source before upload. The package must stay within SLC v1 limits:

  • Uncompressed source: at most 50 MiB.
  • Compressed archive: at most 50 MiB.
  • Included files: at most 5,000.

Use .gitignore or .ignore to keep build output, local caches, private files, and temporary artifacts out of the upload.

Never include .env files, tokens, beta codes, provider credentials, or private logs in the project package.

Run:

Terminal window
beamup deploy

If the deploy succeeds, check:

Terminal window
beamup status
beamup --app hello-gleam logs --no-follow

Open the dashboard cockpit and confirm the app has:

  • Active deployment.
  • Runtime logs.
  • Build logs.
  • Health state.
  • Safe runtime snapshot or a clear snapshot-unavailable warning.

For private beta feedback, record:

  • Original app shape and framework.
  • Whether the app was already Erlang-targeted.
  • Whether it already read PORT.
  • Whether it already had a clean health path.
  • Any beamup.toml fields you changed.
  • Any runtime values you moved to beamup env set.
  • Whether the app reached a live URL without founder command help.
  • App runs locally but does not read PORT: change startup config to read the runtime PORT env var.
  • App binds only to 127.0.0.1: bind HTTP traffic on 0.0.0.0:<PORT>.
  • Health path depends on a database: use a lightweight process-ready path for activation.
  • Secret is in beamup.toml: move it to beamup env set --secret.
  • App target is JavaScript: not supported in SLC v1.
  • App expects custom domain setup: custom domains are not supported in SLC v1.

For field-level config rules, see beamup.toml Reference and Supported Apps And Limitations.