Skip to main content
Version: Canary

Any Container Host

Cedar's single-container topology works out of the box, with no per-platform integration to write or maintain, on any host that builds from a package.json and runs yarn start. That covers a wide range of platforms:

  • Railway (Railpack)
  • Render
  • Google Cloud Run
  • DigitalOcean App Platform (Paketo)
  • Heroku
  • Coolify (Nixpacks/Railpack)
  • Dokku
  • Dokploy
  • Koyeb
  • Northflank

None of these need a Cedar-specific setup deploy command — they all build and run the same way.

The conventions

Every generated Cedar app ships these package.json scripts:

"build": "cedar build",
"dev": "cedar dev",
"start": "cedarjs-server",
"start:api": "cedarjs-server api",
"start:web": "cedarjs-server web"

A buildpack-style builder (Railpack, Nixpacks, Paketo, Google Cloud buildpacks, Heroku's buildpack) finds build and start and runs them automatically. start runs both sides in one process — the single-container topology — so there's no service-to-service wiring for the platform to get right.

The server also reads the two environment variables every container host sets automatically:

  • PORT — the port to listen on. Set by the platform; Cedar's public-facing side binds to it automatically.
  • HOST — the host to bind. Cedar defaults to ::, which binds dual-stack (IPv4 and IPv6) on hosts that support it, so this rarely needs to be set explicitly.

So the setup on any of these platforms is: connect the repo, point the build command at yarn build, point the start command at yarn start, add a DATABASE_URL. Nothing Cedar-specific beyond that — except migrations, which every database-backed app needs regardless of platform. See below.

Migrations

Every Cedar app with a database needs yarn cedar prisma migrate deploy run once per deploy — after the build finishes, before the new version starts taking traffic. This is the one piece that doesn't fit the "no platform-specific setup" story above: there's no build-tool convention for "run this command once, at the right moment, per deploy," so each platform needs its own answer.

Don't run it from inside start if you have multiple replicas or overlapping deploys. The instances could race to migrate the same database concurrently.

  • Platforms with a dedicated pre-deploy or release hook (Railway's Pre-Deploy Command, Heroku's release phase in the Procfile) run it there — see Railway.
  • Platforms without one, like Coolify, fold it into the build command or run it as a one-off command against the deployed container — see Coolify.
  • Render's yarn cedar setup deploy render generator already handles this for you — see Render.
  • For a platform not documented here (Cloud Run, DigitalOcean, Dokku, Dokploy, Koyeb, Northflank), look for that platform's equivalent of a pre-deploy, release, or init hook before falling back to a manual one-off run.

Custom server file caveat

If your app has a custom server file (api/src/server.ts), start won't work on any of these platforms — a custom server file is a Fastify concept with no equivalent in the single-container in-process server, so it refuses to start rather than silently skipping what you configured. You'll need the two-service topology instead, which means per-platform wiring — see Railway and Coolify.

devDependency pruning caveat

Two platforms in the list above strip devDependencies after the build step by default: Heroku and DigitalOcean App Platform (Paketo). start resolves the cedarjs-server bin from @cedarjs/api-server, which is a root dependency (not a devDependency) specifically so this works — but if pruning removes more than expected, or you've moved something into devDependencies that start needs, you'll see the deploy succeed and the container fail immediately with a "command not found" error.

If you hit that, disable pruning:

  • Heroku: set NPM_CONFIG_PRODUCTION=false or YARN_PRODUCTION=false
  • DigitalOcean App Platform: set YARN2_SKIP_PRUNING=true or NPM_CONFIG_PRODUCTION=false

The other platforms in the list (Railway, Render, Cloud Run, Coolify, Dokku, Dokploy, Koyeb, Northflank) don't prune by default, so this doesn't apply to them.

Scaling up: the two-service topology

Every platform above can also run the recommended two-service topologystart:api and start:web as two separate services — once you outgrow single-container. That split is inherently more platform-specific: the web service needs to know where the api service lives, and how you wire that (a proxy target, an internal DNS name, a private-network URL) differs per platform. See Railway and Coolify for two platforms where that wiring is documented end to end.