Skip to content

Go to the docs contents

while.yaml

while.yaml, at the root of your app, says what it needs. Your agent writes it, and this page lists every field.

Updated November 9, 2026.

View as Markdown

while.yaml
apiVersion: while/v1
project: planning
services:
  - name: web
    port: 3000
    health: { path: /health }
databases:
  - name: main

This file describes a project: its services, its databases, its caches, its storage, its queues, its scheduled jobs, its domains, its environments. while builds its infrastructure. A project without a web service is allowed, if it declares at least a database or a scheduled job.

The file

FieldTypeWhat it does
apiVersion (required)always while/v1The format version: always while/v1.
project (required)text (lowercase)The project’s identifier, in lowercase.
serviceslist of servicesThe app’s services. They are optional when the project declares at least a database or a scheduled job: a data project does not always have a web service.
databaseslist of databases, or of other projects’ databasesThe project’s PostgreSQL databases, or databases of other projects that it reads. Four at most.
cacheslist of cachesThe project’s Valkey caches, which speak the Redis protocol. Four at most.
bucketslist of bucketsThe project’s S3 buckets, for its files. Four at most.
cronslist of scheduled jobsThe scheduled jobs: a command run at a fixed time, in a service’s image, or built for it when the project has no service. Each run is tracked (history, failures, missed runs), and can be run again or caught up on request.
environmentsobjectThe settings specific to an environment. The key is the environment’s name: production, preview…
telemetryobjectWhat while keeps of the app: its logs, its metrics, its traces and its errors.
telemetry.logstrue or falsetrue keeps the app’s output in its logs. Default: true.
telemetry.metricstrue or falsetrue counts the app’s requests, errors and response times. Default: true.
telemetry.tracestrue or falsetrue keeps the app’s OpenTelemetry traces. Default: false.
telemetry.errorstrue or falsetrue gives the app a Sentry-compatible entry point, whose address (DSN) while provides. Default: true.
telemetry.uptimeobjectAn availability probe: a path of the app, called at a regular interval.
networkobjectThe app’s network egress. The Internet is CLOSED to it by default (egress: restricted): an external API is declared as a connection (declare_connection), while adds its key and goes over IPv4 if needed, and the app calls it through <NAME>_URL. egress: all opens the Internet directly, after a person’s approval. A change holds at the next deployment.
network.egressnone, restricted, allnone closes all access to the Internet. restricted (default) closes the Internet, except the declared connections and the allow list, which go through while’s egress. all opens the Internet directly, over IPv6 as over IPv4, after approval. Default: restricted.
network.allowlist of textsThe host names allowed when egress is restricted. They are called through while’s egress, never directly. For an API that requires a key, prefer a connection.

Services

Each entry in services describes a service: a site, an API, a worker or a static site.

FieldTypeWhat it does
name (required)text (lowercase)The service’s name, in lowercase. It goes into its address and into SERVICE_<NAME>_URL.
descriptiontextA line for whoever opens the service, under its title on the page of their apps (“Today’s sales, per store”): 140 characters at most, with nothing technical. Without it, the page shows the address.
typeweb, worker, staticweb: an HTTP service, with its address. worker: a process without an address or an HTTP probe, such as a job queue or a consumer. static: a static site, served with an HTTP cache. Default: web.
roottextFor a static site: the folder to serve once the site is built (dist, build, public…). Default: ..
sourcetextThe path of the sources in the uploaded archive, or in the git repository. Default: ..
imagetextAn image already built, in an external registry or in while’s, preferably with its digest.
dockerfiletextThe path of the Dockerfile. Without it, while recognizes the language and writes the Dockerfile.
buildobjectThe build of the service’s image.
build.contexttextThe build’s context folder. Default: ..
build.targettextThe Dockerfile stage to build (—target).
build.argsobjectThe build arguments (—build-arg), not secret: they stay in the image’s history and provenance. A name that looks like a secret (TOKEN, KEY, SECRET, PASSWORD) is refused: go through secrets.
build.secretslist of textsThe names of the build secrets, such as NPM_TOKEN. Their value is set separately, with set_env { build: true } or the “for the build” box of the settings, never here. They are mounted for the time of a RUN in /run/secrets/<NAME>, never in the image, and masked in the log. A build never reads the app’s secrets, and the app does not receive the build’s.
build.testtextThe test command, run in the same sandbox as the build. By default, that of the recognized language.
build.skip_teststrue or falsetrue does not run the tests when building this service. Default: false.
commandlist of textsThe command that starts the service, instead of the image’s, for example ["node", "server.js"].
portintegerThe port the service listens on. while gives it to the app in the PORT variable. Default: 8080. From 1 to 65535.
publictrue or falsetrue exposes the service on a public domain. Default: true.
accesspublic, internalpublic opens the service to the whole Internet. internal puts it behind while’s connection, or the company’s: the app receives the identity in X-While-Email, X-While-Name, X-While-Groups and X-While-Identity. Without groups, emails or email_domains, the organization’s members get in. Making an internal app public, or changing who gets in, requires an approval. Default: public.
emailslist of textsFor internal access: the addresses that get in, members of the organization or not.
domainslist of textsThe service’s custom domains. while always gives it its default address too.
healthobjectThe health probe: while calls this path every second, and a version only receives traffic once it answers 2xx or 3xx.
health.pathtextA path of the app. It starts with a single ”/”, without a full address, without ”//”, without a backslash or a space. Default: /health.
health.initial_delay_secondsintegerThe delay before the probe’s first call, in seconds. Default: 0.
health.timeout_secondsintegerThe time the probe waits for an answer, in seconds. Default: 3.
health.startup_timeout_secondsintegerThe time a new version has to answer its probe, in seconds, before being refused (the live version keeps the traffic). 120 by default, 900 at most: for an app that migrates its database at startup (Metabase, Keycloak). A truly broken version then takes that long to be declared failed. Default: 120. From 30 to 900.
envobjectThe environment variables. A value { secret: path } is read from while’s vault.
resourcesobjectThe processor and memory reserved for each instance of the service.
resources.cpuCPU (500m, 1)A processor quantity: 500m for half a vCPU, 1 for one vCPU. Default: 200m.
resources.memorymemory (256Mi, 1Gi)A memory quantity: 256Mi, 1Gi. Default: 192Mi.
resources.diskdisk (1Gi)For a worker or a task: the /tmp disk, on the node’s disk and not in memory, which is also the container’s storage limit. 1 GiB by default, 8 GiB at most. No effect on a web service, whose /tmp is taken from its memory. Default: 1Gi.
volumevolumeNot open yet on this platform: deployment refuses a volume. A disk that survives deployments, restarts and the loss of a node, for a worker or a task, mounted by one instance at a time. Removed from the while.yaml, it is kept 7 days, then destroyed.
scaleobjectThe number of instances of the service, between min and max.
scale.minintegerThe number of instances kept as long as the service does not sleep (see sleep). 0 is the old way of saying sleep: 30m: prefer sleep. Default: 1. From 0 to 5.
scale.maxintegerThe cap of instances when traffic rises: 10 at most if scale.max is not declared. Default: 1. From 1 to 5.
useslist of textsThe databases, caches, storages or queues this service uses. By default, everything the project declares.
titletextThe title people see, written from the point of view of whoever uses it (“Sales reading”, “Order import, every hour”): 80 characters at most, on one line, with nothing technical. Without a title, the screens show the name.
sleepdelay (30m, 2h) or neverPutting a web service or a static site to sleep. A delay (30m, 2h) puts it to sleep after that time without a request: the next request wakes it up in a few seconds, and waits for its answer. no (or false) always keeps at least one instance. By default: no in production, 30m in the other environments, such as previews. A sleeping service restarts with one instance on wake-up: scale.min only counts if it does not sleep. A worker never sleeps, nor does a production database.
groupslist of textsFor internal access: the organization’s groups that get in, made in while or coming from the enterprise connection.
memberstrue or falseFor internal access with groups, emails or email_domains: true also lets the organization’s members in. Without this field, only the lists get in. Without lists, the members already get in.
email_domainslist of textsFor internal access: the email domains that get in. A domain holds exactly: nextmap.io does not open fr.nextmap.io.
connectionslist of connection namesThe organization’s connections, external APIs declared in while, that this service or task calls. For “meteo”, the app receives METEO_URL, the relay’s address, token included. The key stays in while, and each call is traced.

Databases

Each entry in databases declares a PostgreSQL database. An entry with from reads another project’s database, without creating anything.

FieldTypeWhat it does
name (required)text (lowercase)The database’s name, in lowercase. It goes into its variables, such as DB_<NAME>_URL.
enginepostgresThe database engine: postgres, the only one. Default: postgres.
versiontextThe PostgreSQL version: 16, 17 or 18. Default: 17.
sizememory (256Mi, 1Gi)The database’s disk, billed per GiB per month. Default: 1Gi.
computeS, M, L, XLAn instance’s size: the reserved processor and memory, with the PostgreSQL and pooler settings that follow. S: 0.1 vCPU and 256 MB (up to 1 GB). M: 0.5 vCPU and 1 GB. L: 1 vCPU and 4 GB. XL: 2 vCPU and 8 GB. A size change restarts the database. Do not confuse it with size, the disk. Default: S.
pooltransaction, sessionThe mode of the pooler (PgBouncer) in front of the database. transaction, the default: each transaction can take another server connection; many clients for few connections, but what depends on a session only lasts its transaction. session: one server connection per connected client, kept as long as it stays connected; the pooler accepts no more clients than the database size has connections (S 20, M 60, L 100, XL 140), the extra client is refused. Choose session for an app that needs its session: Liquibase migrations (Metabase, Keycloak) or Flyway, which take a session advisory lock, a session advisory lock taken by the app, LISTEN/NOTIFY, a temporary table. Default: transaction.
instances1, 2 or 3The number of PostgreSQL instances of the database. With 1, a single instance runs on a node’s disk, and a node failure is repaired by a restore. With 2 or 3, the database is highly available: one or two standby instances are kept up to date continuously, and take over on their own if the primary falls. Each instance has its own disk (size). Do not confuse it with replica, a read replica for query_database.
replicatrue or falsePlanned: a read replica, kept up to date continuously, which the agents’ query_database tool will read. The field is accepted already. As long as the replica is not served, query_database reads the primary, in a read-only transaction, and says so in its answer. Default: false.
backupobjectThe database’s backups.
backup.scheduletextThe time of the day’s full backup, in cron format, in UTC. Default: 0 3 * * *.
backup.retention_daysintegerRead but not followed: while keeps backups 14 days, for all databases. Default: 7.
backup.test_restoretrue or falsewhile replays the restore of each backup, and shows the result. Default: true.

Read another project’s database

The database of another project of the same organization, which this project’s apps read: nothing is created. The first deployment that declares it requires the approval of that database’s approvers. Once approved, each reading app receives DB_<NAME>_URL, DB_<NAME>_USER and DB_<NAME>_PASSWORD, a read-only access that the approvers can restrict to schemas, tables or columns. A database of another organization is refused.

FieldTypeWhat it does
nametext (lowercase)Its name in this project, which makes the DB_<NAME>_URL variable. By default, <project>-<database> (DB_ENTREPOT_MAIN_URL).
from (required)text<project>/<database>: a project of the same organization, and the name of its database.
accessreadread: the only value, read-only. Default: read.
environmenttextThe source database’s environment. Default: production.
readerslist of textsThe apps that read it: a service, or task:<name>. Without this field, all those of the project.

Caches

Each entry in caches declares a Valkey cache, which speaks the Redis protocol.

FieldTypeWhat it does
name (required)text (lowercase)The cache’s name, in lowercase. It goes into its variables, such as CACHE_<NAME>_URL.
enginevalkeyThe cache engine: valkey, the only one. Default: valkey.
memorymemory (256Mi, 1Gi)The memory reserved for the cache. Default: 64Mi.
durabletrue or falsetrue keeps the data on disk (AOF journal), without ever evicting it: for a job queue (BullMQ, Sidekiq, Celery). Without it, a restart empties the cache. Default: false.

Buckets

Each entry in buckets declares an S3 bucket.

FieldTypeWhat it does
name (required)text (lowercase)The bucket’s name, in lowercase. It goes into its variable, such as S3_BUCKET_<NAME>.
publictrue or falsetrue opens the reading of objects to everyone, without a key, after an approval. Default: false.
corslist of textsThe extra origins from which a browser opens a presigned URL of this bucket (https://host[:port]). The app’s are already there.

Scheduled jobs

The scheduled jobs: a command run at a fixed time, in a service’s image, or built for it when the project has no service. Each run is tracked (history, failures, missed runs), and can be run again or caught up on request.

FieldTypeWhat it does
name (required)text (lowercase)The task’s name, in lowercase.
schedule (required)textThe schedule in cron format, with 5 fields, in the timezone’s zone (Europe/Paris by default): “0 3 * * *” runs the task every day at 3 am.
command (required)list of textsThe command to run, for example ["node", "cron.js"].
servicetext (lowercase)The service whose image and variables the task takes: the first service by default. Without a declared service, or with image, source, dockerfile or build, the task is built for itself.
imagetextAn image already built for a task without a service, preferably with its digest.
sourcetextFor a task without a service: the path of the sources in the uploaded archive, or in the git repository. Default: ..
dockerfiletextFor a task without a service: the path of the Dockerfile. Without it, while recognizes the language.
buildobjectThe build of the service’s image.
build.contexttextThe build’s context folder. Default: ..
build.targettextThe Dockerfile stage to build (—target).
build.argsobjectThe build arguments (—build-arg), not secret: they stay in the image’s history and provenance. A name that looks like a secret (TOKEN, KEY, SECRET, PASSWORD) is refused: go through secrets.
build.secretslist of textsThe names of the build secrets, such as NPM_TOKEN. Their value is set separately, with set_env { build: true } or the “for the build” box of the settings, never here. They are mounted for the time of a RUN in /run/secrets/<NAME>, never in the image, and masked in the log. A build never reads the app’s secrets, and the app does not receive the build’s.
build.testtextThe test command, run in the same sandbox as the build. By default, that of the recognized language.
build.skip_teststrue or falsetrue does not run the tests when building this service. Default: false.
envobjectThe environment variables. A value { secret: path } is read from while’s vault.
useslist of textsFor a task without a service: the databases, caches, storages or queues it uses. By default, everything the project declares.
resourcesobjectBy default, those of the service taken, and 100 mCPU and 128 MiB for a task without a service.
resources.cpuCPU (500m, 1)A processor quantity: 500m for half a vCPU, 1 for one vCPU.
resources.memorymemory (256Mi, 1Gi)A memory quantity: 256Mi, 1Gi.
resources.diskdisk (1Gi)For a worker or a task: the /tmp disk, on the node’s disk and not in memory, which is also the container’s storage limit. 1 GiB by default, 8 GiB at most. No effect on a web service, whose /tmp is taken from its memory.
volumevolumeNot open yet on this platform: deployment refuses a volume. A disk that survives deployments, restarts and the loss of a node, for a worker or a task, mounted by one instance at a time. Removed from the while.yaml, it is kept 7 days, then destroyed.
timeout_secondsintegerThe maximum duration of a run. Beyond it, the run is stopped and counted as “timed out”. Default: 600. From 10 to 21600.
retriesintegerThe number of new attempts after a failure, within the same run. Default: 0. From 0 to 5.
concurrencyforbid, allow, replaceforbid prevents two runs at the same time, and refuses a manual run as long as another one runs. allow permits overlap. replace makes the new run stop the current one. Default: forbid.
timezonetextThe schedule’s time zone, as an IANA name: Europe/Paris, UTC… Default: Europe/Paris.
titletextThe title people see, written from the point of view of whoever uses it (“Sales reading”, “Order import, every hour”): 80 characters at most, on one line, with nothing technical. Without a title, the screens show the name.
connectionslist of connection namesThe organization’s connections, external APIs declared in while, that this service or task calls. For “meteo”, the app receives METEO_URL, the relay’s address, token included. The key stays in while, and each call is traced.

Environments

The settings specific to an environment. The key is the environment’s name: production, preview…

FieldTypeWhat it does
fromtext (lowercase)The reference environment this one inherits from.
serviceslist of objectsThe services’ settings in this environment.
databaseslist of objectsThe databases’ settings in this environment.
ttl_hoursintegerThe lifetime before automatic destruction, for a preview environment. From 1 to 720.

The full schema

The JSON schema of while.yaml is public, at https://app.while.sh/schema/while.v1.json. Your agent reads it to check its file before deploying.

Connect your agent, it takes care of the rest

To paste into your agent

Read while.sh/agents, then deploy my app with while.

Copy the instructions

No account needed to try: your app is live right away. To keep it, sign in.

A project for your company? Talk to the team: hello@while.sh