Documentation

Docs

What Shippers is, how to deploy a WebforJ or Spring app, and how to drive it all from the shippers CLI — including wiring shippers deploy into CI/CD.

Overview

Shippers is one-click hosting for untrusted, third-party builds — you upload, Shippers runs it in an isolated container and hands back a live URL. See how it works for the full deploy pipeline and pricing for trial/plan details.

Supported frameworks

WebforJ (.war or an executable Spring Boot .jar, auto-detected) and Spring (.jar) are the two supported application frameworks today, both deployed from a single upload. React/Flutter/Angular/Next.js (static export)/plain HTML deploy the same way, as static builds.

One-click deploy

Create an app, drag in your build, and get a live URL at yourapp.shippers.cloud — no server setup, no Dockerfile to write.

Isolated by default

Every deployed app runs in its own hardened container with hard CPU/memory/pid limits and no host networking, since Shippers hosts strangers' untrusted uploads.

Trial & quotas

Every account starts on a 7-day free trial (no card required) with a 1-app cap. Pro lifts that to 3 apps, 3 managed databases, and CLI access.

Managed databases

Provision an internal-only PostgreSQL or MySQL instance and wire its connection details into your app's environment variables — no separate hosting to manage. See connecting to a database below.

Environment variables

Set per-app env vars from the dashboard or via shippers env push. Changes take effect on the next deploy.

Deploying a WebforJ app

WebforJ apps can be uploaded as either a .war (run in Tomcat) or an executable Spring Boot .jar (webforJ's Spring Boot integration) — Shippers detects which one you've uploaded from the file itself, so nothing needs to be configured up front. The JDK version is also auto-selected to match whatever your project was compiled against.

1

Create an app

From the dashboard, choose "WebforJ" as the framework. This only decides which file types the upload step accepts — it doesn't lock you into WAR or JAR ahead of time.
2

Build your app

Package it the way you normally would — mvn package for a traditional WAR, or your Spring Boot build (mvn package / gradle bootJar) if you're using webforJ's Spring Boot starter.
3

Upload the build

Drag in the resulting .war or .jar file. Shippers deploys it at the app's root path (/) and hands back a live yourapp.shippers.cloud URL once it's up.
4

Redeploy any time

A later upload can freely switch between a WAR and a JAR — Shippers picks up the new format automatically, no app settings to change first.

Deploying a Spring app

A Spring app is always uploaded as an executable Spring Boot .jar — the same fat-jar produced by spring-boot-maven-plugin's repackage goal or Gradle's bootJar task. Shippers runs it directly with java -jar, choosing the JDK image that matches your compiled bytecode.

1

Create an app

From the dashboard, choose "Spring" as the framework.
2

Build an executable jar

mvn package or gradle bootJar — make sure the Spring Boot Maven/Gradle plugin's repackage step actually runs, since a plain, non-repackaged jar won't be accepted.
3

Upload the jar

Drag in the .jar. Shippers force-binds the container to port 8080 regardless of your own server.port, so SERVER_PORT is a reserved environment variable name — set your app's other config as regular env vars instead.
4

Go live

Once the app reports ready, it's reachable at yourapp.shippers.cloud.

Connecting to a database

A database is provisioned independently of any one app, from the database step of "Create a deployment" or the Databases section of your dashboard. It's internal-only — reachable from your own Shippers apps over the private network, never from the public internet — so there's no external client access (no DBeaver, no migrations run from your laptop). Its detail page shows five separate connection fields — Host, Port, Database, Username, and a reveal-to-view Password — rather than one connection string, and you wire those into your app through environment variables, not by baking them into your build.

How environment variables work

  • Set them from an app's "Environment variables" section on its detail page (or ahead of the first deploy, on the upload step of "Create a deployment"), or from the CLI with shippers env push.
  • Only PORT (Node.js) and SERVER_PORT (Spring Boot's server.port) are reserved — nothing database-related is, so name your own keys however your app expects them.
  • Up to 50 variables per app, values capped at 4096 characters each.
  • Changes only take effect on your next deploy — Docker can't mutate an existing container's environment, so a plain start/stop restart keeps whatever was set at the last deploy. Push or save your values, then redeploy.

WebforJ

Wiring depends on which artifact you're deploying (see deploying a WebforJ app above) — only the Spring Boot path gets automatic wiring.

Spring Boot .jar (webforJ's Spring Boot integration)

1

Link the database

Open the app's "Environment variables" section and click "Link a database" — pick your database from the list and confirm. This inserts three keys for you: SPRING_DATASOURCE_URL (built as jdbc:postgresql://<host>:<port>/<database> or the mysql equivalent), SPRING_DATASOURCE_USERNAME, and SPRING_DATASOURCE_PASSWORD.
2

Add the matching driver dependency

Make sure your pom.xml/build.gradle has org.postgresql:postgresql or com.mysql:mysql-connector-j on the classpath, alongside spring-boot-starter-data-jpa (or -jdbc). Spring Boot's relaxed-binding datasource auto-configuration reads those three env vars with no datasource bean of your own.
3

Redeploy

Env var changes need a new deploy to take effect, not just a restart — upload again or run shippers deploy.

Plain .war (Tomcat, no Spring Boot)

Tomcat does no property binding of its own, so nothing wires a datasource automatically — you read the connection details back yourself.

1

Set your own connection env vars

Copy the Host/Port/Database/Username/Password fields from the database's detail page and set them as env vars under names your own code expects, e.g. DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD. ("Link a database" still works here too — it just prefills the Spring-named keys as plain, harmless env vars; a WAR won't read them on its own either way.)
2

Build the connection in your own startup code

Read the env vars with System.getenv(...) and build a JDBC connection yourself, e.g. via HikariCP:
Java
HikariConfig config = new HikariConfig();
config.setJdbcUrl(
    "jdbc:postgresql://" + System.getenv("DB_HOST") + ":" +
    System.getenv("DB_PORT") + "/" + System.getenv("DB_NAME"));
config.setUsername(System.getenv("DB_USER"));
config.setPassword(System.getenv("DB_PASSWORD"));

DataSource dataSource = new HikariDataSource(config);
3

Redeploy

Like any other env var change, this only takes effect on the next deploy.

Spring

A Spring app is always an executable Spring Boot jar, so the wiring is always the automatic path — identical to webforJ's Spring Boot case above.

1

Link the database

From your app's "Environment variables" section, click "Link a database", pick the database, and confirm. This fills in SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME, and SPRING_DATASOURCE_PASSWORD for you, built from the database's own Host/Port/Database/Username/decrypted Password.
2

Add the matching driver dependency

org.postgresql:postgresql or com.mysql:mysql-connector-j, alongside spring-boot-starter-data-jpa (or -jdbc). No datasource bean of your own is required — Spring Boot's relaxed binding auto-configures one from the env vars directly.
3

Redeploy

Env var changes only apply on the next deploy — push or save your values, then redeploy.
4

Leave SERVER_PORT alone

Shippers force-binds Spring Boot's embedded server to 8080 via the reserved SERVER_PORT key — don't reuse that name for anything else, including a second datasource.

The shippers CLI

Pro

Deploy from your own machine or CI instead of dragging a file into the browser.

The CLI is a Pro-only feature — a trialing account can still deploy from the dashboard, but can't create or use a CLI token. Create one from your profile's "CLI access" panel after upgrading.

bash
npm install -g @shippers/cli

Commands

shippers login [token]

Authenticate with a personal access token (created from the dashboard). Omit the argument to be prompted; pass it directly for non-interactive use, e.g. in CI.

shippers init

Link the current directory to a shippers app — creates one or links an existing one, then writes a .shippers.json file recording the app ID. Interactive only.

shippers deploy [file]

Deploy the linked app. With no argument, zips the current directory (excluding .git/node_modules, respecting .shippersignore/.gitignore); or pass a prebuilt .war/.jar directly. Streams status until the deploy finishes or fails.

shippers env pull [file]

Write the linked app's environment variables to a local file (default .env).

shippers env push [file]

Upload environment variables from a local file — a full replace, not a merge. Redeploy for the new values to take effect.

shippers apps

List every app in your account and its current deployment status.

Integrating the CLI into CI/CD

shippers deploy works the same in CI as it does on your laptop — the only difference is authenticating without a terminal to type into.

1

Create a CLI token

From your profile's "CLI access" panel, create a token and store it as a secret in your CI provider (e.g. SHIPPERS_TOKEN in a GitHub Actions repo secret). The raw token is shown once — copy it immediately. Give it a name that identifies the pipeline using it, so you can revoke just that one later without affecting others.
2

Link the project once, locally

Run shippers init on your own machine to create or link the app, then commit the .shippers.json file it writes to your repo. init is interactive (it asks which app to link), so it isn't something CI can run — but once .shippers.json exists in the repo, shippers deploy needs no further linking step.
3

Authenticate non-interactively

shippers login accepts the token as an argument instead of prompting, so a CI step can call it directly with the secret from step 1:
bash
shippers login "$SHIPPERS_TOKEN"
4

Deploy on every push

A minimal GitHub Actions workflow — install Node, install the CLI, log in, deploy:
.github/workflows/deploy.yml
name: Deploy to Shippers
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install the shippers CLI
        run: npm install -g @shippers/cli

      - name: Authenticate
        run: shippers login "$SHIPPERS_TOKEN"
        env:
          SHIPPERS_TOKEN: ${{ secrets.SHIPPERS_TOKEN }}

      - name: Deploy
        run: shippers deploy
5

Other CI providers

There's nothing GitHub-specific about the CLI — any CI system that gives you Node 20+, a place to store a secret, and outbound network access works the same way:
bash
# Works the same on GitLab CI, CircleCI, Buildkite, etc. — the CLI
# only needs Node 20+ and a network path to api.shippers.cloud.
npm install -g @shippers/cli
shippers login "$SHIPPERS_TOKEN"
shippers deploy

Good to know

  • Node.js hosting isn't available yet — WebforJ and Spring are the two application frameworks supported today, alongside static builds (React/Flutter/Angular/Next.js static export/plain HTML).
  • A CLI deploy polls for up to 3.5 minutes before giving up, matching the dashboard — a cold Spring Boot build with a large dependency set can take a while on first deploy.
  • Env vars pushed via shippers env push only take effect on the next deploy, not an in-place restart — push them before the deploy step, not after.
  • Downgrading off Pro immediately breaks any token's CLI access — a scheduled pipeline will start failing at the shippers login step until the account is Pro again.
  • Revoke a token any time from your profile without affecting others — each CI pipeline should get its own token rather than sharing one across projects.

Ready to automate your deploys?

Upgrade to Pro for CLI access, or start free and deploy from the dashboard first.