Deployment
Choose where state lives
Pick between a managed database and a volume for a service's state, provision it, and know what happens to the data on a deploy.
A container’s own filesystem is temporary: anything a service writes there is gone the moment the container is replaced, on a restart, a new deployment or a rollback. Anything that has to outlive a deploy belongs in a database Lessly runs for you or on a volume you attach to the service.
Where each action lives:
| Surface | Database and volume actions |
|---|---|
| Product App | Both kinds of database are created from the environment canvas, under Add service → Databases. A managed service’s side panel carries Overview, Connect, Backups, Logs and Settings. Managed Postgres lives on the product-level Databases page, which sits outside the environments in the navigation, with Databases and Backups tabs per instance and Resize and Delete on the instance itself. A volume’s Detach volume and Delete volume are on its own side panel — but creating and resizing a volume is tool-only: the Product App carries no screen for it. |
| CLI | Every action on this page: the CLI renders the same operation catalog as MCP. Run it from your own terminal. |
| MCP | Every action on this page. Tool names are linked per section. |
| REST | Every action on this page, under /deployment/…. Browse the endpoints. |
Choose the place
| Where state lives | What it is | Reach for it when |
|---|---|---|
| Managed service in an environment | PostgreSQL, MySQL, Redis or MongoDB running next to your services in the same environment. Created in seconds, no setup beyond a name and a size. (Recommended) over a volume for anything that is a database. | You want storage a service can reach immediately, scoped to one environment. |
| Managed Postgres | A dedicated Postgres instance that belongs to the product rather than to one environment. Carries automated backups with point-in-time recovery, and can be resized to more CPU and RAM. (Recommended) over a volume for anything that is a database. | You want one instance behind several environments, or you need point-in-time recovery. |
| Volume | A persistent disk you attach to one service and mount at a path of your choosing. | The state is not a database: uploaded files, a search index, a cache you would rather not rebuild. |
The two managed options are equals — you pick one per database, by what you want from it. A volume is not a third database: it costs a short gap in service on every deploy, restart and rollback, which neither managed option does.
Provision a managed service in an environment
- On the environment canvas, open Add service → Databases and choose the engine. Give it a name; a slug is derived from it — lowercase letters, digits and dashes, starting with a letter. The slug must be unique within the environment, and it is also the hostname your services use to reach the database.
- Accept the defaults or change them: the engine version, storage (5 GiB by default, from 1 to 1024 GiB), and, for PostgreSQL, MySQL and MongoDB, the name of the initial database (
appby default). - Wait for it. Creation is asynchronous — the database moves through
provisioningtoready. If it cannot come up it lands inprovisioning_failedwith the error kept on the record, and you can retry provisioning without recreating it. - Wire a service to it by referring to the connection variables it publishes, as
${{<slug>.<KEY>}}— for example${{cache.URL}}for a Redis database whose slug iscache. Nothing is injected automatically. - Redeploy the service, so the reference is resolved into the release.
Through the Lessly MCP server: deployment_managed_service_provision, deployment_managed_service_list and deployment_managed_service_types. Token scope: a key with write access to the environment’s databases.
Engines and versions
| Engine | Versions | Default |
|---|---|---|
| PostgreSQL | 15, 16, 17 | 16 |
| MySQL | 8.0, 8.4 | 8.4 |
| Redis | 7, 8 | 7 |
| MongoDB | 7, 8 | 8 |
What each engine publishes
| Engine | Keys |
|---|---|
| PostgreSQL | HOST, PORT, USER, PASSWORD, DATABASE, URL, DATABASE_URL, PGHOST, PGPORT, PGUSER, PGPASSWORD, PGDATABASE |
| MySQL | HOST, PORT, USER, PASSWORD, DATABASE, URL, DATABASE_URL, MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_URL |
| Redis | HOST, PORT, PASSWORD, URL |
| MongoDB | HOST, PORT, USER, PASSWORD, DATABASE, URL, MONGODB_URI |
The database’s page lists every key with the exact reference to copy and marks which ones are secret. The aliases carry the same values as the plain keys; they exist because many libraries read a particular name. Anything holding a password or a full connection string is a secret and is treated as one wherever variables are shown — see Set variables and secrets.
Every engine requires authentication, and the credentials are generated for you. The database is reachable only from services in the same environment, over the private network — it has no public address.
Statuses and what they allow
The full set is provisioning, provisioning_failed, ready, stopping, stopped, starting, resizing, backing_up, restoring and deleting. Actions are accepted only from the status that makes sense for them: you cannot resize a database that is restoring, and stop applies only to a database that is ready.
| Action | Requires | What it does |
|---|---|---|
| Resize | ready | Grows the storage. Increase only — shrinking is not supported. |
| Stop | ready | Shuts the database down, keeping its storage and its credentials. Costs no compute; nothing can connect, so stop the services that use it first. |
| Start | stopped | Brings it back with the same data. |
| Delete | — | Removes the database and its storage. |
MCP: deployment_managed_service_resize, deployment_managed_service_stop, deployment_managed_service_start, deployment_managed_service_delete.
Backups and restore
- On the schedule: every
readydatabase is backed up daily at 03:00 UTC. - On demand: you can take a backup at any time while the database is
ready. It runs online — the database keeps serving. - Retention is 7 days for everything, manual backups included. There is no keep-forever option. If a snapshot has to outlive that window — before a migration, say — export the data yourself.
The backup list shows each snapshot with the time it was taken and whether it is ready to restore from. The last backup timestamp is written only once a snapshot is confirmed ready, so it can lag the real last backup by up to a day; an empty value means “none recorded yet”, not “no backups”.
You restore in place, choosing one snapshot from the list. The database must be ready or stopped to start, and moves through restoring back to ready. Restoring replaces the current contents of the database with the contents of the snapshot — take a fresh backup first if the current data still matters.
MCP: deployment_managed_service_backup, deployment_managed_service_backup_list, deployment_managed_service_restore, deployment_managed_service_connect_info.
Provision Managed Postgres
Managed Postgres is a dedicated Postgres instance provisioned for your product. A product can have several instances, and each instance holds several logical databases that you attach to services in any of the product’s environments. You manage them on the product-level Databases page, which sits outside the environments in the navigation — an instance list, with Databases and Backups tabs per instance.
- Create an instance with a label of your own, a Postgres major version — 16, 17 or 18, defaulting to 18 — and a tier. Creating the first Managed Postgres database from the canvas provisions a
defaultinstance for you if the product has none yet. - Create a logical database on the instance, with an optional label. Its actual database and role names are generated. It is created independently of any service.
- Attach the database to a service. Both the instance and the database must be ready first.
- Redeploy the service. Attaching injects
DATABASE_URL,PGHOST,PGPORT,PGUSER,PGPASSWORDandPGDATABASEinto it as secret service-level variables, which behave like any other secret variable.
| Tier | |
|---|---|
db-custom-1-3840 | the default |
db-custom-2-7680 | |
db-custom-4-15360 |
- An instance can be resized to another tier later, and deleted once it holds no databases — the delete is refused while any database or attachment is still on it.
- One database can be attached to several services at once.
- Detaching removes exactly the six injected variables again, and deleting a database detaches it from every service first.
- Passwords are never returned by Lessly — not in the instance view, not in the database view. The connection string reaches your service as a secret variable and nowhere else.
MCP: deployment_cloud_sql_instance_create, deployment_cloud_sql_instance_resize, deployment_cloud_sql_database_create, deployment_cloud_sql_database_attach, deployment_cloud_sql_database_detach.
Backups, restore and observations
| What holds | |
|---|---|
| Automatic backups | Every night, with point-in-time recovery. 7 days of backups and transaction logs are kept. |
| On-demand backups | Available at any time; the instance stays available while one runs. |
| The Backups tab | Lists the backup runs with their type, start and end times and outcome, read live from the instance. |
| Restore | Picks one of those runs and restores the instance in place. |
| Backup and recovery settings | Reported together with the time that answer was last read back from the instance. A blank value means the setting has not been observed yet — it never means “disabled”. |
A Managed Postgres restore is destructive over the whole instance — every database on it. The dialog asks you to type the instance label to confirm, and the instance is unavailable while it runs, which takes several minutes.
MCP: deployment_cloud_sql_instance_backup, deployment_cloud_sql_instance_backup_list, deployment_cloud_sql_instance_restore.
Create a volume
A volume belongs to one environment and is mounted into one service at a path of your choosing. What the service writes there stays there across restarts, deploys and rollbacks. Creating a volume is tool-only by design: the Product App carries no screen for it.
- Give it a name of up to 80 characters. A slug is derived from it, and you can set the slug yourself.
- Set the size in GB, from 1 to 1024.
- Set the mount path — an absolute path inside the container, for example
/var/lib/data. This is where the volume appears to your code. - Name the service to attach it to. It must live in the same environment as the volume.
- Deploy the service. The mount takes effect on its next deployment.
Creation is the only point at which a volume is bound to a service. A volume created without one stays unattached, and the way to give a service a volume later is to create another one.
The volume starts in provisioning and becomes ready. If provisioning fails it lands in failed with the reason kept on the volume, and a volume attached to nothing shows as detached. Volumes appear on the environment canvas, both as their own node and on the card of the service they are mounted into, which lists the mount path and size.
MCP: deployment_volume_create, deployment_volume_list, deployment_volume_get.
What a volume costs you on every deploy
| The service | How it is deployed |
|---|---|
| Without volumes | The new release starts alongside the old one and traffic switches over once the new one is healthy. No gap in service. |
| With a volume mounted | Only one container can hold the disk at a time, so the old container is stopped first and the new one started afterwards. The service is briefly unavailable on every deploy, restart and rollback. |
That is the trade for persistence. If a service must never have a gap, keep its state in a managed database and leave the service without a volume.
The data itself is unaffected. A new deployment gets the same disk with the same contents at the same path; the volume outlives the container, the release and the rollback.
Resizing, detaching and deleting
| Action | Rule |
|---|---|
| Resize | Tool-only by design as well. A volume can be grown at any time, up to the same 1024 GB ceiling. It cannot be shrunk — a size smaller than the current one is refused. Growing does not move or rewrite the data. |
| Detach | Separates the volume from its service; the data is preserved and the volume goes to detached. The service loses the mount on its next deployment. This is one-way — a detached volume cannot be attached to another service afterwards. |
| Delete | Destroys the volume and everything on it, permanently and with no backup taken. Refused while the volume is still attached, so detach first. The confirmation asks you to type the volume’s slug. |
Because a volume is bound to its service when it is created, detach it only when you are done with it or about to delete it.
MCP: deployment_volume_resize, deployment_volume_detach, deployment_volume_delete.
Next steps
- Set variables and secrets: wire a service to a managed database with
${{slug.KEY}}instead of handling the credentials yourself. - Run a command inside a service: run a migration as a separate run, without touching the replicas serving traffic.
- Scale a service: plan around the deploy gap a mounted volume forces on a service.
- Understand how deployment works: which environment a database or a volume belongs to, and why that is the boundary.