Back to Blog
Tutorial8 min read2026-07-17

How to Deploy a Gleam (Wisp) Web App in 2026

Gleam is a friendly, type-safe language on the Erlang BEAM, and Wisp is its web framework. Here's how to build a Gleam web app into a release and deploy it as a container on PandaStack.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

Every year a new language quietly wins over the developers who try it, and lately that language is Gleam (https://gleam.run). It's a small, friendly, statically-typed functional language that compiles to Erlang and runs on the BEAM — so you inherit decades of battle-tested concurrency and fault tolerance, with a type system and error messages that don't make you cry. Wisp (https://gleam.run/frameworks/) is its pragmatic web framework. Deploying a BEAM app used to mean learning rebar3 incantations; Gleam plus a container makes it genuinely simple. I run PandaStack; here's the path.

A tiny Wisp app

A minimal handler in src/app.gleam:

import gleam/erlang/process
import gleam/http/response.{type Response}
import mist
import wisp.{type Request}
import wisp/wisp_mist

pub fn handle_request(req: Request) -> Response(wisp.Body) {
  case wisp.path_segments(req) {
    [] -> wisp.html_response("<h1>Hello from Gleam on PandaStack</h1>", 200)
    ["health"] -> wisp.json_response("{\"ok\":true}", 200)
    _ -> wisp.not_found()
  }
}

pub fn main() {
  wisp.configure_logger()
  let secret = wisp.random_string(64)
  let assert Ok(_) =
    wisp_mist.handler(handle_request, secret)
    |> mist.new
    |> mist.port(8080)
    |> mist.start_http
  process.sleep_forever()
}

Note the port 8080 — a host only needs your app to listen on a known port, and this one does. (Read the port from an env var if you want it configurable; Gleam has envoy and similar libraries for that.)

Step 1: Build a release

Gleam builds through its own tooling. Locally:

gleam deps download
gleam run    # dev
gleam export erlang-shipment   # produces a self-contained release in build/erlang-shipment

The erlang-shipment export bundles your compiled app so it can run with just an Erlang runtime — no Gleam toolchain needed at runtime.

Step 2: Dockerfile

A two-stage build: compile with the Gleam image, run on a slim Erlang base.

FROM ghcr.io/gleam-lang/gleam:v1.6.0-erlang-alpine AS build
WORKDIR /app
COPY . .
RUN gleam deps download
RUN gleam export erlang-shipment

FROM erlang:27-alpine
WORKDIR /app
COPY --from=build /app/build/erlang-shipment ./
EXPOSE 8080
# the shipment includes an entrypoint script
CMD ["./entrypoint.sh", "run"]

Pin the Gleam and Erlang versions to what your project targets — both move, and mismatches are the most common deploy failure here.

Step 3: Deploy on PandaStack

  1. 1Push to Git.
  2. 2https://dashboard.pandastack.io → New App → connect the repo. PandaStack detects the Dockerfile, builds it with rootless BuildKit, and deploys via Helm.
  3. 3Set any environment variables (secrets, config) in the encrypted env store.
  4. 4Expose port 8080. Add a custom domain under Domains — SSL is automatic.
  5. 5Every push redeploys.

CLI:

npm install -g @pandastack/cli
panda login
panda deploy

Step 4: Add a database

Gleam has Postgres libraries (like pog). Provision managed PostgreSQL on PandaStack (Databases → New Database → PostgreSQL), attach it to the app, and read DATABASE_URL from the environment. A quick connect:

import pog
import gleam/erlang/os

pub fn connect() {
  let assert Ok(url) = os.get_env("DATABASE_URL")
  // parse the URL and start a pog connection pool...
}

The BEAM's process model makes connection pooling and concurrency feel natural — this is where running on Erlang pays off.

Step 5: Health checks and the BEAM's superpower

Point PandaStack's health check at /health. The nice thing about a BEAM app is that supervision trees keep parts of your app alive even when others crash — but the container-level health check is still your backstop: if the whole VM wedges, the platform restarts it. Belt and suspenders.

Honest tradeoffs

  • Gleam's ecosystem is young. The language and stdlib are lovely, but you'll find fewer libraries than in Node or Python. Check that what you need exists before committing a production service.
  • Versions move. Gleam and its libraries iterate quickly — pin everything and expect to bump versions deliberately.
  • BEAM cold starts are reasonable but the runtime image isn't tiny; free-tier scale-to-zero adds some cold-start latency. Keep it warm on a paid tier for latency-sensitive endpoints.
  • PandaStack is a newer platform too — great DX, growing ecosystem.

Wrap-up

Gleam gives you a type-safe, friendly language on the rock-solid BEAM; Wisp gives you a clean web framework; gleam export erlang-shipment plus a two-stage Dockerfile gives you a portable container. Deploy it on PandaStack with Git-push, managed Postgres, automatic SSL, and health checks. A delightful stack that actually ships.

Docs: https://docs.pandastack.io. Start free: https://dashboard.pandastack.io.

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also