---
title: app.yml
slug: optimizely-connect-platform/docs/app-structure-appyml-ocp2
docTags: 
createdAt: 2026-07-23T12:37:04.808Z
---

Define your app in the `app.yml` file, including store details, runtime, functions, and jobs that your app uses.

## `meta` section of `app.yml`

The `meta` section of the `app.yml` file describes the basic elements of your app. It includes the following fields:

- `app_id` – The unique identifier of your application in Optimizely Connect Platform (OCP).
- `display_name` – The name that displays for your app in the OCP **App Directory**.
- `version` – The version of your app that displays in the OCP **App Directory**. The experimental `ocp app deploy` command ignores this field and derives the version from the content of your app. See [Deploy to preview tracks](docId\:gLoc5c6DPRHSfUcBL6bpf).
- `vendor` – The name your organization publishes apps under, which displays in the OCP **App Directory**. The OCP CLI populates this automatically from your organization when you scaffold the app.
- `summary` – The description of your app that displays in the OCP **App Directory**.
- `support_url` – The support URL for your app or company that displays in the OCP **App Directory**.
- `contact_email` – The email customers contact for questions or issues with your app.
- `categories` – Tag the app for sorting in the OCP **App Directory**. See the following options:
  - `Advertising`
  - `Channel`
  - `Commerce Platform`
  - `Content Management`
  - `Lead Capture`
  - `Loyalty & Rewards`
  - `Marketing`
  - `Merchandising & Products`
  - `Offers`
  - `Productivity`
  - `Reviews & Ratings`
  - `Site & Content Experience`
  - `Subscriptions`
  - `Surveys & Feedback`
- `availability` – The global regions where you want to make the app available. See the following options:
  - `us` – United States (required)
  - `eu` – Europe
  - `au` – Asia-Pacific
  - `all` – All current and future available deployment regions.

Below is an example of the `meta` section of the `app.yml` file for a data integration app between OCP and Bynder.

```javascript
meta:
  app_id: bynder
  display_name: Bynder
  version: 1.0.4
  vendor: Optimizely
  summary: Integrate Bynder with Optimizely
  support_url: https://support.optimizely.com/
  contact_email: support@optimizely.com
  categories:
    - Marketing
  availabiity:
   - us
```

The following image shows how this example app displays in the OCP App Directory:

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/yW-rbKYG3R5VEAxPhBDd7_da0853eeebfa42d25ceaa6dcf133e1f93b6220b5cf2766fbbbfb3098415db323-image.png)

And how it displays when users select the app in the OCP App Directory.

::Image[]{src="https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/9xB4fnAtg7VbSo8KiL6t3_450766d4e6fbab4104d6e110e4d4726c5c5fb24ad3e251ce852dc6696d69f2d0-image.png" size="50" isUploading="false" width="279" height="563" darkWidth="279" darkHeight="563" showCaption="false"}

## `sources` section of `app.yml`

The `sources` section defines custom data sync sources that users can select when creating data syncs in the OCP Sync Manager. For detailed information on building sources, see [Data sync source](docId:6hgAikH6TMV9ClfpfPARu).

Each source requires:

- `description` – Human-readable description of the source's purpose.
- `schema` – Either a string referencing a static schema name (a `.yml` file in `src/sources/schema/`) or an object with `entry_point` for dynamic schemas.

```yaml
sources:
  # Static schema example
  product_sync:
    description: Sync products from external system
    schema: product

  # Dynamic schema example
  custom_sync:
    description: Sync with dynamically discovered fields
    schema:
      entry_point: CustomSchemaFunction
```

To emit data to a source, use the `sources.emit()` API from any function or job. See [Data sync source](docId:6hgAikH6TMV9ClfpfPARu) for implementation details.

## `ui_extensions` section of `app.yml`

:::hint{type="success"}
**Beta**

The following feature is in beta.
:::

The `ui_extensions` section declares the UI panels that a CMS UI extension app contributes to Optimizely CMS. This section is required only for CMS UI extension apps. Other app types omit it.

CMS UI extension apps also use a dedicated runtime — set `runtime: node22-cms-ext` instead of `node22`. The `accepts: cms_ui_extension` attribute on a function marks it as the backend proxy invoked from the UI bundle. Use `accepts` only on functions invoked through `context.extension.invokeFunction()`. Other functions in the same `functions:` section omit it.

```yaml
runtime: node22-cms-ext

functions:
  cms_extension:
    entry_point: CmsUiExtension
    description: Backend proxy for the UI extensions.
    accepts: cms_ui_extension

ui_extensions:
  sidebar:
    - name: my-extension
      entry_point: MyExtension
      display_name: My Extension
  view:
    - name: my-gallery
      entry_point: MyGallery
      display_name: My Gallery
  property-editor:
    - name: my-color-picker
      entry_point: MyColorPicker
      display_name: My Color Picker
      metadata:
        property_type: string
        property_format: shortstring
```

Each `ui_extensions` injection point maps to a list of entries. OCP supports the content editor side panel, `sidebar`, a full page, `view`, and a custom editor for a single content property, `property-editor`. Additional panel types are planned. Declare any combination of keys. Each entry requires:

- `name` – Unique identifier for the extension within the app.
- `entry_point` – Basename of the UI source file under `src/cms-ui-extensions/` without the injection-point suffix and extension. The build emits the matching bundle to `dist/cms-ui-extensions/<entry_point>.js`.
- `display_name` – The label the CMS editors can view.

A `property-editor` entry also requires a `metadata` block that declares the property it edits:

- `property_type` – (Required) One of `string`, `richtext`, `integer`, `float`, or `boolean`.
- `property_format` – (Optional) Only `string` accepts a format, `shortstring`. Omit it for every other type.

`name` and `entry_point` must be unique across the whole `ui_extensions` section, not only within one injection point.

See [CMS UI extensions](docId\:NV6r9sjdc_6Dhs0_dvf6S) for the full feature reference.

## Complete `app.yml` file example

The following is a complete example of an `app.yml` file:

```yaml
meta:
  app_id: sample_app
  display_name: Sample App
  version: 1.0.0
  vendor: optimizely
  summary: A sample app
  support_url: https://www.optimizely.com
  contact_email: support@optimizely.com
  legal_url: https://optimizely.com/privacy_policy
  categories:
    - Commerce Platform
  availability:
    - all

runtime: node22

environment:
  - APP_ENV_GLOBAL_SECRET

sources:
  product_sync:
    description: Sync products from external catalog
    schema: product

functions:
  handle_event:
    entry_point: HandleEvent
    description: Transforms incoming data into OCP events

  product_webhook:
    entry_point: ProductWebhook
    description: Receives product updates and emits to source

jobs:
  historical_import:
    entry_point: HistoricalImport
    description: Performs a one-time historical import when triggered

  nightly_import:
    entry_point: NightlyImport
    # runs at midnight every night
    cron: 0 0 0 ? * *
    description: Performs a nightly import for data that is not provided or needed in real time

liquid_extensions:
  generate_coupon:
    entry_point: GenerateCoupon
    description: Generates a unique coupon code
    input:
      rule:
        type: string
        required: true
        description: The coupon rule to create the coupon from
      email:
        type: string
        required: false
        description: Email address to tie the coupon code to

channel:
  type: facebook_messenger
  targeting:
    - identifier: sample_app_messenger_id
  options:
    prepare: true
```

## Data integration example

This example app pulls data from an email service provider (ESP). The `import` job can handle both the historical import and hourly pulls. The `GetEspLists` function lets you pull lists from the ESP so you can import them.

```yaml
meta:
  app_id: esp_collect
  display_name: ESP Collection App
  version: 1.0.0
  vendor: optimizely
  summary: An app that imports contacts and activity
  support_url: https://www.optimizely.com
  support_email: support@optimizely.com
  categories:
    - Marketing Automation

runtime: node22

functions:
  get_esp_lists:
    entry_point: GetEspLists
    description: Pulls the lists from the ESP to select which ones you want imported

jobs:
  import:
    entry_point: Import
    description: Performs a one-time historical import when triggered
    # Runs every hour
    cron: 0 0 * * * ?
```

## CMS UI extension example

:::hint{type="success"}
**Beta**

The following feature is in beta.
:::

The following example shows a CMS UI extension app. It uses the `node22-cms-ext` runtime, declares one sidebar extension and one full-page view extension, and pairs them with a backend function marked `accepts: cms_ui_extension`.

```yaml
meta:
  app_id: my_cms_ext
  display_name: My CMS Extension
  version: 1.0.0
  vendor: optimizely
  summary: A UI extension for Optimizely CMS
  support_url: https://www.optimizely.com
  contact_email: support@optimizely.com
  categories:
    - Content Management
  availability:
    - all

runtime: node22-cms-ext

functions:
  cms_extension:
    entry_point: CmsUiExtension
    description: Backend proxy for the UI extensions.
    accepts: cms_ui_extension

ui_extensions:
  sidebar:
    - name: my-extension
      entry_point: MyExtension
      display_name: My Extension
  view:
    - name: my-gallery
      entry_point: MyGallery
      display_name: My Gallery
```
