Create a token
Railway |
Project settings → Tokens. Account tokens: railway.com/account/tokens |
Render |
Dashboard → Account Settings → API key. Shown in full only once |
Fly.io |
fly tokens create deploy -a <app> --name ci --expiry 48h
(copy all of it, FlyV1
prefix included) |
Vercel |
vercel.com/account/tokens. vercel tokens add "CI deploy"
works only if you already use a classic account token; a vercel login
session can't make one |
Heroku |
heroku authorizations:create -d "ci" -e 86400 -S
( -e
in seconds; no expiry if left out) |
DigitalOcean |
cloud.digitalocean.com/account/api/tokens |
Cloudish |
POST /api/v1/keys
(cloudish.ai), no credential needed (see the Cloudish block) |
Give the token to your script
Railway |
|
Project token: one environment in one project |
Railway |
|
Account token (broadest) or workspace token (one workspace) |
Render |
|
API key. Unlike render login
tokens, it doesn't expire on its own |
Fly.io |
|
A deploy token covers one app |
Vercel |
|
A personal token from your account |
Heroku |
|
Overrides the token saved by heroku login
|
DigitalOcean |
DIGITALOCEAN_ACCESS_TOKEN
|
An API token; or pass --access-token
per command |
Cloudish |
|
One key; it can't spend past its prepaid balance |
No browser on the machine?
Railway |
railway login --browserless
(for SSH sessions) |
Render |
Skip login
; the token variable above is enough |
Fly.io |
Skip login
; the token variable above is enough |
Vercel |
Skip login
; the token variable above is enough |
Heroku |
Skip login
; the token variable above is enough |
DigitalOcean |
With DIGITALOCEAN_ACCESS_TOKEN
set, doctl auth init
saves it with no prompt |
Cloudish |
Nothing to log in to: the first call returns the key |
Deploy
Railway |
RAILWAY_TOKEN=xxx railway up
(add --ci
to stream only build logs and exit when the build completes) |
Render |
render deploys create <service-id> --output json --confirm --wait
|
Fly.io |
fly deploy
(uses the settings in fly.toml
; builds remotely by default) |
Vercel |
vercel deploy --prod --yes > url.txt
(stdout is the deploy URL) |
Heroku |
heroku container:login
, then heroku container:push web -a <app>
, then heroku container:release web -a <app>
|
DigitalOcean |
First time: doctl apps create --spec app.yaml --wait
. Later: doctl apps create-deployment <app-id> --wait
|
Cloudish |
POST /api/v1/projects
(cloudish.ai) with a tar.gz of the folder (see the Cloudish block) |
Did it work?
Railway |
railway up
exits 0
when the deploy reaches SUCCESS
, 1
if it fails. --ci
exits once the build completes. With --detach
: poll railway deployment list --json
|
Render |
--wait
blocks; a failed deploy exits non-zero |
Fly.io |
Watches the deploy until the machines are healthy (--wait-timeout, default 5 min); --detach returns at once. Then: fly status -a <app>
|
Vercel |
Exit code not 0
= error; read stderr |
Heroku |
No wait flag. Check heroku releases -a <app>
and heroku ps -a <app>
|
DigitalOcean |
--wait
gives up after 30 min by default ( --wait-timeout 1h
for longer); the deploy itself keeps running |
Cloudish |
Poll GET /api/v1/images/builds/<id>
until status
is succeeded
or failed
|
Read logs
Railway |
railway logs
· build: railway logs --build
· last 100: railway logs -n 100
|
Render |
render logs --resources <service-id> --tail
( --resources
is required in scripts) |
Fly.io |
fly logs -a <app>
streams; --no-tail
prints the buffer and exits |
Vercel |
vercel logs --deployment <url-or-id> --json
(default: last 30 min, 100 records) |
Heroku |
heroku logs --tail -a <app>
· heroku logs -n 200 -a <app>
(Cedar apps, the generation before Fir: up to 1,500 lines) |
DigitalOcean |
doctl apps logs <app-id> web --type build
( build
, deploy
or run
; add --follow
to stream) |
Cloudish |
GET /api/v1/docker/<alias>/<app>/logs
|
Cloudish: the whole flow in curl
# 1. Get a key. No account, card or browser.
curl -X POST $API/keys \
-H "content-type: application/json" \
-d '{"alias": "my-app"}'
# -> "key": "cld_...", "apiKey": {"alias": ...}
export CLOUDISH_API_KEY=cld_...
# Keep the key out of chat and logs.
ALIAS=my-app # the apiKey.alias in the answer
AUTH="Authorization: Bearer $CLOUDISH_API_KEY"
# 2. Pack the folder (Dockerfile at its root),
# minus secrets.
tar --exclude='.env*' --exclude='.git' \
-czf context.tar.gz .
# 3. Build on Cloudish's servers and deploy.
# No local Docker.
curl -X POST $API/projects -H "$AUTH" \
-F name=my-app -F port=8080 \
-F context=@context.tar.gz
# -> "build": {"id": 123, "status": "pending"}
# 4. Wait for the build, then URL and logs.
curl $API/images/builds/123 -H "$AUTH"
curl $API/projects/$ALIAS/my-app -H "$AUTH"
# The URL is in subdomain.url.
curl $API/docker/$ALIAS/my-app/logs -H "$AUTH"
|
Cloudish errors you'll meet
503
"nothing accepts connections on port …" |
port
doesn't match the port your server listens on (default 8080
) |
"Job has reached the specified backoff limit" |
The build most likely ran out of CPU or memory; retry with buildCpuCores
/ buildMemoryGb
|
|
The key's balance is zero. Builds and deploys answer 402
; running apps stop within a minute, volumes kept |
Gotchas by host
Railway |
A script never creates a project on its own. Link one first ( railway up --new
creates one), or the run fails with NOT_AUTHENTICATED
or a no-project error |
Railway |
Set only one of RAILWAY_TOKEN
and RAILWAY_API_TOKEN
; both at once is an error |
Railway |
Raw API calls with a project token use the Project-Access-Token
header, not Authorization: Bearer
|
Fly.io |
Deploy tokens last 20 years unless you set --expiry
|
Vercel |
If --token
and VERCEL_TOKEN
are both set, the flag wins |
Heroku |
container:push
needs Docker on your machine. Heroku documents this flow for Cedar-generation apps only |
Heroku |
heroku auth:token
gives a token valid for 1 year; use authorizations:create
for CI |
DigitalOcean |
doctl apps create
needs App Platform to have access to your repo |
Cloudish |
The claimUrl
(which lets a person take over the key) works once and expires in 30 minutes |
Keep tokens safe
- Put the token in an environment variable, not a flag. Vercel's docs warn that command-line arguments "can be visible in process lists and logs".
- Pick the narrowest token: a Railway project token over an account token, a Fly deploy token over an org token.
- Give it an end date: Fly --expiry 48h
, Heroku -e 86400
. Render API keys don't expire on their own, so revoke them in the dashboard when done.
- Revoke: fly tokens list
, then fly tokens revoke <id>
. Vercel: vercel tokens rm <id>
.
- Never paste a key into chat, code or logs, and keep .env
files out of anything you upload. |
Which host fits
You need a fully automated workflow |
Cloudish: the only one of the seven where the script creates its own key. On the others, a person signs up and makes the token first. (Without an account, a person can still try two others: vercel deploy --temporary puts a folder online, not in CI, until someone claims it; ssh railway.new gives a Linux VM to claim within 24 hours.) |
You need a managed Postgres database |
Railway ( railway add --database postgres
) or Render (Render Postgres). Cloudish has none; you run the database inside your container on a volume |
A person iterates on a frontend app |
Vercel |
Sources (as of 2026-10-26)
|
Created By
Metadata
Comments
No comments yet. Add yours below!
Add a Comment
Related Cheat Sheets