> For the complete documentation index, see [llms.txt](https://docs.carto.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.carto.com/carto-for-developers/reference/hosted-apps/app-manifest.md).

# App manifest (carto.json)

The carto.json file a hosted app ships to declare the Named Sources CARTO registers when it is deployed

{% hint style="info" %}
**Private Preview:** Hosted Apps is available to selected accounts during its Private Preview. To request access, contact your CARTO representative.
{% endhint %}

`carto.json` declares the backend a hosted app needs: the connections it uses and the [Named Sources](/carto-user-manual/developers/named-sources.md) it runs by name instead of sending SQL from the browser. CARTO reads it when you run `carto app deploy`, validates it, registers the Named Sources it declares, and keeps it to remove them when the app is deleted.

## Where it lives

The manifest is a file named exactly `carto.json` at the **root of the bundle directory** you pass to `carto app deploy`. The CLI reads it and leaves it out of the upload, so it is **never served** and its SQL never reaches a browser. A `carto.json` in a subdirectory is treated as an ordinary file.

With Vite, place it in the `public` folder so that the build copies it to the root of `dist`.

The manifest is optional, and so is every field in it. An app that only reads tables the user already has access to needs no `carto.json`.

{% hint style="info" %}
`carto app schema` prints this contract as JSON Schema, with every field described, and runs offline. Use `carto app schema connection`, `source`, `migration` or `carto-info` for one section, and `--json` for the compact form.
{% endhint %}

## Top-level fields

| Field         | Type                | Required | Constraints        | Description                                                                                                               |
| ------------- | ------------------- | -------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------- |
| `name`        | string              | No       | None               | Informational. The app takes its name from `carto app deploy --name`, which defaults to the name of the bundle directory. |
| `apis`        | array of string     | No       | At most 10 entries | The CARTO APIs the app uses: `sql`, `maps`, `lds`, `imports`, `ai`. Informational; see [Declared APIs](#declared-apis).   |
| `connections` | array of connection | No       | At most 20 entries | The connections the app declares Named Sources on.                                                                        |

Unknown top-level keys are ignored.

## `connections[]`

| Field        | Type            | Required | Constraints                                                                      | Description                                                                                                                       |
| ------------ | --------------- | -------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `name`       | string          | Yes      | Non-empty                                                                        | The name of a connection in your organization, or a handle you map at deploy time. See [Connection handles](#connection-handles). |
| `provider`   | string          | Yes      | One of `postgresql`, `bigquery`, `redshift`, `snowflake`, `databricks`, `oracle` | The warehouse provider of the connection. Use `bigquery` for the CARTO Data Warehouse.                                            |
| `sources`    | object          | No       | At most 200 entries                                                              | Named Sources, keyed by a short name. See [`sources`](#sources).                                                                  |
| `namespace`  | string          | No       | Matches `/^[a-z_][a-z0-9_]*$/`                                                   | Reserved. Accepted, but not used by the current release.                                                                          |
| `migrations` | array of object | No       | At most 200 entries                                                              | Reserved. Accepted, but not used by the current release.                                                                          |

A connection can also list `tables` and `statements`. They are only used by `carto app check` and `carto app package` to scope the token of a public build, and `carto app deploy` ignores them.

### Connection handles

`connections[].name` can be the name of a connection in your organization, or a **handle** that you map to one at deploy time:

```bash
carto app deploy ./dist --connection warehouse=my_bigquery
```

The flag is repeatable, and also accepts a comma-separated list (`--connection a=c1,b=c2`). A handle that is not mapped is used as a connection name.

Before registering the Named Sources of a connection, CARTO checks that the connection exists in your organization. If it does not, the deploy fails with `No access to connection "<name>"`.

Named Sources are not tied to a connection: the app's code passes the real connection name (`connectionName`) each time it runs one.

### `sources`

Each key in `sources` is the short name of one Named Source, and its `sql` is the parametrized query.

| Field | Type   | Required | Constraints                           | Description                                                                              |
| ----- | ------ | -------- | ------------------------------------- | ---------------------------------------------------------------------------------------- |
| `sql` | string | Yes      | Non-empty, at most 100,000 characters | The SQL query. Use `@param` placeholders for the values the app sends with each request. |

How they work:

* **The SQL is not sent to the browser.** The app sends the name of the source and its parameters, and CARTO runs the stored query. See [Avoid exposing SQL queries with Named Sources](/carto-for-developers/guides/avoid-exposing-sql-queries-with-named-sources.md).
* **Each source is registered as `<slug>_<key>`.** A source keyed `stores_in_state` in an app with the slug `retail-stores` is run as `retail-stores_stores_in_state`. The full name must follow the Named Sources naming rule, `/^[a-z0-9][a-z0-9\-_]{2,50}(?<![-_])$/`: 3 to 51 lowercase letters, digits, `-` and `_`, starting with a letter or a digit and not ending in `-` or `_`. The slug and the underscore count towards the 51 characters.
* **They are regular Named Sources**, created by the user who deploys the app and listed in their Developers > Named Sources.
* **They run with the credentials of the user** who opens the app, not those of the owner. A user without permission on the connection gets an error.
* **The SQL is run as written** for the connection's warehouse. Besides `SELECT`, a source can be an `INSERT`, `UPDATE` or `DELETE`; the warehouse credentials the connection uses must then be allowed to write to the table.

Their lifecycle follows the app:

* Each deploy creates or updates the sources listed in `carto.json` before it uploads the files. The version being served uses the new SQL from that moment, even if the deploy then fails.
* A source you remove from `carto.json` is not deleted; remove it in Developers > Named Sources.
* Deleting the app removes the sources listed in its latest `carto.json`.
* A rollback does not change them. See [Versions](/carto-for-developers/reference/hosted-apps/runtime-and-authentication.md#versions).
* If a deploy fails, the sources it registered before the error remain. Fix the error and deploy again.

### Declared APIs

`apis` records which CARTO APIs the app uses. It is informational: it is not a token scope and does not limit what the app can call. A hosted app always runs with the permissions of the signed-in user.

## Complete example

```json
{
  "name": "Retail stores",
  "apis": ["sql", "maps"],
  "connections": [
    {
      "name": "warehouse",
      "provider": "bigquery",
      "sources": {
        "stores_in_state": {
          "sql": "SELECT cartodb_id, storetype, revenue, geom FROM `carto-demo-data`.demo_tables.retail_stores WHERE state = @state"
        },
        "store_set_revenue": {
          "sql": "UPDATE `my_project`.retail.stores SET revenue = @revenue WHERE cartodb_id = @id"
        }
      }
    }
  ]
}
```

Deployed with `carto app deploy ./dist --slug retail-stores --connection warehouse=my_bigquery`, this registers `retail-stores_stores_in_state` and `retail-stores_store_set_revenue`, which the app runs with `connectionName: 'my_bigquery'`.

## Validation errors

The CLI validates the manifest before uploading anything, and CARTO validates it again when you deploy.

| Message                                                       | Cause                                                                                                      |
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `Invalid carto.json: <message>`                               | The file is not valid JSON.                                                                                |
| `carto.json: <path>: <message>`                               | A field is invalid or a list is over its limit. `<path>` locates it, for example `connections.0.provider`. |
| `No access to connection "<name>"`                            | The connection does not exist in your organization. Check the name and any `--connection` mapping.         |
| `Invalid named source name "<slug>_<key>" (from key "<key>")` | The full name breaks the naming rule above. Use a shorter key or slug.                                     |

## Related

* [Runtime and authentication](/carto-for-developers/reference/hosted-apps/runtime-and-authentication.md): what the app reads at runtime, and whose credentials it uses.
* [`app` command reference](/carto-for-agents/cli/command-reference/app.md): `carto app deploy` and `carto app schema`.
* [Named Sources](/carto-user-manual/developers/named-sources.md): the platform feature the manifest registers into.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.carto.com/carto-for-developers/reference/hosted-apps/app-manifest.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
