Skip to main content

The manifest

apphaven.yaml, in the root of your repository, describes your application to AppHaven. It declares three things:

AppHaven validates the manifest and uses it to run your app. To change your app's shape, edit apphaven.yaml and push; the next deploy picks it up.

A complete example

A web service built from the repository's Dockerfile, a managed database, and a persistent volume for uploads:

version: 1

services:
web:
type: container
build:
dockerfile: Dockerfile # built from your repository on every deploy
ports:
- 3000 # served on your app's URL
env:
NODE_ENV: production
DATABASE_URL: ${service.db.url} # a ready-to-use connection URL
volumes:
- name: uploads
mount_path: /app/uploads
depends_on:
- service: db
condition: healthy # wait until the database accepts connections

db:
type: postgres # managed database, provisioned by AppHaven
version: "17"

volumes:
uploads:
type: persistent # kept across deploys

With this manifest, AppHaven builds web from the Dockerfile in your repository, provisions the db database with generated credentials, creates the uploads volume, starts web once the database is ready (with DATABASE_URL set to a real connection URL), and serves port 3000 on your app's URL over HTTPS.

Top-level fields

FieldTypeRequiredDescription
versionintnoThe manifest schema version. Currently 1, which is also the default.
servicesmap of name → service specyesYour app's services. At least one is required.
volumesmap of name → volume specnoVolumes your services mount. Required only if a service references a volume.

Naming rule

Every name you choose in the manifest (each service name and each volume name) must match:

^[a-zA-Z0-9][a-zA-Z0-9_\-]{0,63}$
  • Starts with a letter or digit.
  • 1–64 characters long.
  • Contains only letters, digits, underscores (_), and dashes (-).
tip

Use lowercase service and volume names so they're accepted as written.

Validation

AppHaven validates the manifest before anything is deployed. Validation is strict: an unknown field anywhere in the manifest is rejected with a clear error, so a typo fails fast instead of being silently ignored.

When a manifest is rejected, the message describes the problem. Common causes:

CauseExample message
An unknown field (often a typo)service web: unknown field "prots"
A name doesn't match the naming ruleservice name "my app!" is invalid
Unknown service typeservice web: type "vm" not supported
Container with neither image nor buildservice web: image or build is required
A field that isn't valid for the service typeservice db: "ports" is not allowed on a postgres service
Port out of rangeservice web: port 99999 out of range
depends_on cycledepends_on cycle: web -> db -> web
condition: healthy on a target with no healthcheckservice web depends_on db (healthy) but db has no healthcheck
Reference to an unknown service or fieldservice web: ${service.cache.url} references unknown service "cache"
Reference to an undeclared volumeservice web: references undeclared volume "missing"
Non-canonical mount pathservice web: mount_path "/a/../b" must be canonical
Unknown volume typevolume cache: type "weird" not supported

Where to go next