> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vertracloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Template Stacks: Several Apps, Databases and Blob Folders in One Template

> Build a multi-service template: apps, databases and Blob folders created together and wired with placeholders, certificates and the public mode.

A template with two or more services creates a **stack**: one resource that groups the apps, databases and Blob folders, keeps them connected and is updated, snapshotted and deleted as a unit. You do not declare the stack; it exists because `services` has more than one entry (up to 8).

A template with a single app creates just that app, with no stack.

## Declare the services

Each service is an entry of `services`. Apps, databases and Blob folders sit side by side, and the placeholders connect them:

```yaml theme={null}
services:
  app:
    source: { type: image, image: "docker.io/n8nio/n8n@sha256:942bc274709f27f99f7c6024a785d8e8f75ac06838cabcba448abb8d9127ec7b", context: . }
    port: 5678
    ram: { min: 1024, recommended: 2048 }
    web: required
    env:
      DB_POSTGRESDB_HOST: "{{services.db.host}}"
      DB_POSTGRESDB_PORT: "{{services.db.port}}"
      DB_POSTGRESDB_DATABASE: "{{services.db.database}}"
      DB_POSTGRESDB_USER: "{{services.db.user}}"
      DB_POSTGRESDB_PASSWORD: "{{services.db.password}}"
  db:
    database: postgres
    ram: { min: 1024, recommended: 1024 }
```

Everything is created in one job. The order is: validation, the stack, the databases (the job waits for them to be ready), Blob folders, images, apps, variables, certificates, start, healthcheck and outputs. If any step fails, the platform deletes only what that job created, with no safety snapshot because nothing yet holds user data, and reports the step and the error.

### Optional services

Make a database optional with `when`, or switch any service with `sets.services` in a question option. A service that is off is not created and its placeholders are empty. This is how one template offers "Postgres or SQLite" or "add workers"; see [Options and sets](https://docs.vertracloud.app/templates/create/placeholders-and-inputs.md#options-and-sets). The memory of a service that is off does not count towards the required plan.

### Several databases of the same engine

You can declare more than one database of the same engine, such as a Redis for cache and another for a queue. Each is a regular database with its own memory taken from the plan, and each has its own service id and placeholders. A database belongs to one stack only, and several apps of the stack can use the same database.

### Blob folders

A `blob` service gives the stack the folder `stacks/<stack-slug>/` and a key managed by the platform, restricted to that folder. The app reads it through the `S3_*`-style placeholders. If the user undoes the stack, the key is revoked and **the files are kept**. See the [Blob service](https://docs.vertracloud.app/templates/create/manifest-reference.md#blob-folder) for the fields.

## How the services connect

You never write an address. Use `{{services.<id>.host}}` or `{{services.<id>.url}}`. The app reaches the database through its public address, with client certificates. A `network_mode` other than `public` is refused with `STACK_NETWORK_MODE_UNAVAILABLE`.

### Certificates

Databases require a client certificate. The platform writes the files into the app at `/app/.vertra/certs/<database_id>/` at every start, read-only, and `{{services.<id>.ssl.*_path}}` gives you their absolute paths:

| File | Placeholder | Used by |
| - | - | - |
| `ca.pem` | `ssl.ca_path` | All engines |
| `client.crt` | `ssl.cert_path` | Postgres, MySQL, Redis |
| `client.key` | `ssl.key_path` | Postgres, MySQL, Redis |
| `client.pem` | `ssl.pem_path` | MongoDB |
| `client.p12` | `ssl.p12_path` | Prisma 6 (empty password) |

The folder is reserved by the platform: it is skipped by code uploads, snapshot restores, rollbacks, downloads and "Save as template", so a private key never travels with the code. If the user resets the database certificates, the platform rewrites the files and asks them to restart the app.

Some drivers cannot take certificates by path alone. When yours reads them from the connection URL, use `{{services.<id>.url}}`; for Prisma 6, use `{{services.<id>.prisma_url}}`. See [Connect an app to a database](https://docs.vertracloud.app/templates/use/connect-databases.md) for how each driver reads the certificates.

### Connecting app to app

One app reaches another through its public URL, so the called app needs `web: required` or `web: optional` and is **exposed on the internet**. The platform does not authenticate the call: if you want only your own app to be accepted, check a shared secret on both sides:

```yaml theme={null}
secrets: [internal_token]

services:
  web:
    # ...
    env:
      API_URL: "{{services.api.url}}"
      API_TOKEN: "{{secrets.internal_token}}"
  api:
    # ...
    env:
      EXPECTED_TOKEN: "{{secrets.internal_token}}"
```

Your `api` must refuse a request without that token.

## Variables managed by the stack

Variables that come from a placeholder of a database, Blob folder or app are **managed**: they carry a "managed by the stack" badge and update on their own when a password, certificate or address changes. The platform tells the user the app must restart. Editing one by hand turns it into a regular variable.

## Updates

A stack that came from your template updates all its services together: a safety snapshot of every member, then the services one after another, and a full return to the snapshot if one fails. Resources the user added to the stack by hand are ignored by updates. See [Updates and rollback](https://docs.vertracloud.app/templates/use/updates-and-rollback.md).

## Related

> [card] [Placeholders and inputs](https://docs.vertracloud.app/templates/create/placeholders-and-inputs.md)
>
> Every database and Blob placeholder.

> [card] [Stacks for users](https://docs.vertracloud.app/templates/use/stacks.md)
>
> What the user sees and can do with a stack.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.