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.
Step 1: Confirm The Project Root
Section titled “Step 1: Confirm The Project Root”From the app directory, check that gleam.toml exists:
ls gleam.tomlIf your deployable app is inside a subdirectory, remember that path. You can set
it later as app_root in beamup.toml.
Step 2: Confirm The Target
Section titled “Step 2: Confirm The Target”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.
Step 3: Export The Erlang Shipment
Section titled “Step 3: Export The Erlang Shipment”Run:
gleam export erlang-shipmentThe usual BeamUp start command expects the exported entrypoint:
./build/erlang-shipment/entrypoint.sh runIf 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.
Step 4: Read PORT
Section titled “Step 4: Read PORT”Your app must read the PORT environment variable at startup and bind HTTP
traffic to that port.
A local check should look like this:
PORT=8000 ./build/erlang-shipment/entrypoint.sh runThen in another terminal:
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.
Step 5: Add A Health Path
Section titled “Step 5: Add A Health Path”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:
curl -i http://127.0.0.1:8000/healthzStep 6: Create beamup.toml
Section titled “Step 6: Create beamup.toml”Run:
beamup initReview 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.
Step 7: Keep Runtime Values Out Of Config
Section titled “Step 7: Keep Runtime Values Out Of Config”Do not add secrets or runtime env values to beamup.toml.
Invalid:
[secrets]DATABASE_URL = "<database-url>"Use BeamUp runtime configuration instead:
beamup --app hello-gleam env set FEATURE_FLAG=enabledbeamup --app hello-gleam env set DATABASE_URL=<database-url> --secretConfiguration changes apply to future runtime starts. Redeploy after setting a value that the app needs at startup.
Step 8: Check The Package Shape
Section titled “Step 8: Check The Package Shape”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.
Step 9: Deploy
Section titled “Step 9: Deploy”Run:
beamup deployIf the deploy succeeds, check:
beamup statusbeamup --app hello-gleam logs --no-followOpen 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.
Step 10: Record What Changed
Section titled “Step 10: Record What Changed”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.tomlfields you changed. - Any runtime values you moved to
beamup env set. - Whether the app reached a live URL without founder command help.
Common Adaptation Problems
Section titled “Common Adaptation Problems”- App runs locally but does not read
PORT: change startup config to read the runtimePORTenv var. - App binds only to
127.0.0.1: bind HTTP traffic on0.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 tobeamup 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.
