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

# Single-runtime image

> See all of the options for controlling your apps and how they're built and deployed on Upsun.

export const DynamicCodeBlock = ({language = 'yaml', filename, icon, lines, wrap, expandable, highlight, focus, children}) => {
  const STORAGE_KEY = 'upsun_versions_cache';
  const COMPOSABLE_STORAGE_KEY = 'upsun_composable_cache';
  const CACHE_TTL = 5 * 60 * 1000;
  const API_URL = 'https://meta.upsun.com/images';
  const COMPOSABLE_API_URL = 'https://meta.upsun.com/composable';
  const DEBUG_PREFIX = '[DynamicCodeBlock cache]';
  const [versionData, setVersionData] = useState(null);
  const [versionError, setVersionError] = useState(false);
  const [composableData, setComposableData] = useState(null);
  const [composableError, setComposableError] = useState(false);
  useEffect(() => {
    const fetchData = async () => {
      let cachedData = null;
      let cachedEtag = null;
      if (typeof localStorage !== 'undefined') {
        try {
          const cached = localStorage.getItem(STORAGE_KEY);
          if (cached) {
            const parsed = JSON.parse(cached);
            cachedData = parsed?.data || null;
            cachedEtag = parsed?.etag || null;
            if (cachedData && Date.now() - parsed.timestamp < CACHE_TTL) {
              return cachedData;
            }
          }
        } catch (err) {
          console.error('Failed to load from cache:', err);
        }
      }
      const requestHeaders = cachedEtag ? {
        'If-None-Match': cachedEtag
      } : {};
      console.debug(`${DEBUG_PREFIX} revalidating`, {
        storageKey: STORAGE_KEY,
        hasCachedData: Boolean(cachedData),
        hasCachedEtag: Boolean(cachedEtag)
      });
      const response = await fetch(API_URL, {
        headers: requestHeaders
      });
      if (response.status === 304 && cachedData) {
        console.debug(`${DEBUG_PREFIX} revalidated (304)`, {
          storageKey: STORAGE_KEY
        });
        if (typeof localStorage !== 'undefined') {
          try {
            const etag = response.headers.get('etag') || cachedEtag;
            localStorage.setItem(STORAGE_KEY, JSON.stringify({
              data: cachedData,
              etag,
              timestamp: Date.now()
            }));
          } catch (err) {
            console.error('Failed to refresh cache metadata:', err);
          }
        }
        return cachedData;
      }
      if (!response.ok) throw new Error(`API request failed: ${response.statusText}`);
      const data = await response.json();
      const etag = response.headers.get('etag');
      console.debug(`${DEBUG_PREFIX} refreshed (200)`, {
        storageKey: STORAGE_KEY,
        etag
      });
      if (typeof localStorage !== 'undefined') {
        try {
          localStorage.setItem(STORAGE_KEY, JSON.stringify({
            data,
            etag,
            timestamp: Date.now()
          }));
        } catch (err) {
          console.error('Failed to cache data:', err);
        }
      }
      return data;
    };
    fetchData().then(data => setVersionData(data)).catch(err => console.error('Failed to fetch version data:', err));
  }, []);
  const findHighestVersion = versionsMap => {
    if (!versionsMap || Object.keys(versionsMap).length === 0) return null;
    const entries = Object.entries(versionsMap);
    const active = entries.filter(([, v]) => v.upsun && v.upsun.status === 'supported' || v.upsun && v.upsun.status === 'deprecated');
    const candidates = active.length > 0 ? active : entries;
    let [highestName] = candidates[0];
    for (let i = 1; i < candidates.length; i++) {
      const [currentName] = candidates[i];
      const cp = currentName.split('.').map(Number);
      const hp = highestName.split('.').map(Number);
      for (let j = 0; j < Math.max(cp.length, hp.length); j++) {
        if ((cp[j] || 0) > (hp[j] || 0)) {
          highestName = currentName;
          break;
        } else if ((cp[j] || 0) < (hp[j] || 0)) {
          break;
        }
      }
    }
    return highestName;
  };
  const getVersion = (lang, requestedVersion = 'latest') => {
    if (lang === 'composable') {
      if (!composableData || !composableData.versions || Object.keys(composableData.versions).length === 0) return null;
      if (requestedVersion && requestedVersion !== 'latest') {
        return (requestedVersion in composableData.versions) ? requestedVersion : null;
      }
      return findHighestVersion(composableData.versions);
    }
    if (!versionData) return null;
    const imageData = versionData[lang];
    if (!imageData || !imageData.versions || Object.keys(imageData.versions).length === 0) {
      return null;
    }
    if (requestedVersion && requestedVersion !== 'latest') {
      return (requestedVersion in imageData.versions) ? requestedVersion : null;
    }
    return findHighestVersion(imageData.versions);
  };
  let code = typeof children === 'string' ? children : String(children || '');
  const codeLines = code.split('\n');
  while (codeLines.length > 0 && codeLines[0].trim() === '') codeLines.shift();
  while (codeLines.length > 0 && codeLines[codeLines.length - 1].trim() === '') codeLines.pop();
  if (codeLines.length > 0) {
    const indents = codeLines.filter(line => line.trim().length > 0).map(line => line.match(/^[ \t]*/)[0].length);
    const minIndent = Math.min(...indents);
    code = codeLines.map(line => line.slice(minIndent)).join('\n');
  }
  code = code.replace(/\{\{version:(.*?)\}\}/g, (match, params) => {
    const parts = params.split(':');
    const lang = parts[0];
    const ver = parts[1] || 'latest';
    const isComposable = lang === 'composable';
    const hasError = isComposable ? composableError : versionError;
    const dataReady = isComposable ? composableData !== null : versionData !== null;
    if (hasError) return '(unavailable)';
    if (dataReady) {
      const resolvedVersion = getVersion(lang, ver);
      return resolvedVersion || match;
    }
    return '...';
  });
  const codeBlockProps = {
    language,
    ...filename && ({
      filename
    }),
    ...icon && ({
      icon
    }),
    ...lines !== undefined && ({
      lines
    }),
    ...wrap !== undefined && ({
      wrap
    }),
    ...expandable !== undefined && ({
      expandable
    }),
    ...highlight && ({
      highlight
    }),
    ...focus && ({
      focus
    })
  };
  return <CodeBlock {...codeBlockProps}>{code}</CodeBlock>;
};

Use the `.upsun/config.yaml` file,
located at the root of your Git repository, to configure the apps in a single-runtime image.

See a [comprehensive example](/docs/configure-apps#comprehensive-example) of a configuration in
a `.upsun/config.yaml` file.

[Multi-app projects](/docs/configure-apps/multi-app) can be set up in various ways.

## Primary application properties

In the `.upsun/config.yaml` file, configure each application as a unique key beneath the top-level `applications` key.

For example, if your deployed site requires a Javascript `frontend` application container and a Python `backend` application container, the `.upsun/config.yaml` file would start to look something like this:

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        frontend:
          type: 'nodejs:{{version:nodejs:latest}}'
          # Additional frontend configuration
        backend:
          type: 'python:{{version:python:latest}}'
          # Additional backend configuration`
  }
</DynamicCodeBlock>

The following table presents all of the properties available to each unique app beneath the `applications` key.

The **Set in instance** column defines whether the given property can be overridden within a `web` or `workers` instance.
To override any part of a property, you have to provide the entire property.

<Info>
  The `build`, `dependencies`, and `runtime` properties are unique to this image type and are described later in this topic. All other properties are available in both single-runtime and composable images — click a property name to view its details in a separate topic.
</Info>

| Name                                                                           | Type                               | Required | Set in instance? | Description                                                                                                                                                                                                                                                                              |
| ------------------------------------------------------------------------------ | ---------------------------------- | -------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`type`](#type)                                                                | A type                             | Yes      | No               | The base image to use with a specific app language. Format: `runtime:version`.                                                                                                                                                                                                           |
| [`container_profile`](/docs/configure-apps/image-properties/container_profile) | A container profile                |          | Yes              | Determines which combinations of CPU and RAM a container can use.                                                                                                                                                                                                                        |
| [`relationships`](/docs/configure-apps/image-properties/relationships)         | A dictionary of relationships      |          | Yes              | Connections to other services and apps.                                                                                                                                                                                                                                                  |
| [`mounts`](/docs/configure-apps/image-properties/mounts)                       | A dictionary of mounts             |          | Yes              | Directories that are writable even after the app is built. Allocated disk for mounts is defined with a separate resource configuration call using `upsun resources:set`.                                                                                                                 |
| [`web`](/docs/configure-apps/image-properties/web)                             | A web instance                     |          | N/A              | How the web application is served.                                                                                                                                                                                                                                                       |
| [`workers`](/docs/configure-apps/image-properties/workers)                     | A worker instance                  |          | N/A              | Alternate copies of the application to run as background processes.                                                                                                                                                                                                                      |
| [`timezone`](/docs/configure-apps/timezone)                                    | `string`                           |          | No               | The timezone for crons to run. Format: a [TZ database name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). Defaults to `UTC`, which is the timezone used for all logs no matter the value here. See also [app runtime timezones](/docs/projects/change-project-timezone) |
| [`access`](/docs/configure-apps/image-properties/access)                       | An access dictionary               |          | Yes              | Access control for roles accessing app environments.                                                                                                                                                                                                                                     |
| [`variables`](/docs/configure-apps/image-properties/variables)                 | A variables dictionary             |          | Yes              | Variables to control the environment.                                                                                                                                                                                                                                                    |
| [`build`](#build)                                                              | A build dictionary                 |          | No               | What happens when the app is built.                                                                                                                                                                                                                                                      |
| [`dependencies`](#dependencies)                                                | A dependencies dictionary          |          | No               | What global dependencies to install before the `build` hook runs.                                                                                                                                                                                                                        |
| [`hooks`](/docs/configure-apps/image-properties/hooks)                         | A hooks dictionary                 |          | No               | What commands run at different stages in the `build`, `deploy`, and `post_deploy` phases.                                                                                                                                                                                                |
| [`crons`](/docs/configure-apps/image-properties/crons)                         | A cron dictionary                  |          | No               | Scheduled tasks for the app.                                                                                                                                                                                                                                                             |
| [`source`](/docs/configure-apps/image-properties/source)                       | A source dictionary                |          | No               | Details about the app’s source code and available operations.                                                                                                                                                                                                                            |
| [`runtime`](#runtime)                                                          | A runtime dictionary               |          | No               | Customizations to your PHP runtime.                                                                                                                                                                                                                                                      |
| [`additional_hosts`](/docs/configure-apps/image-properties/additional_hosts)   | An additional hosts dictionary     |          | Yes              | Mappings of hostnames to IP addresses.                                                                                                                                                                                                                                                   |
| [`operations`](/docs/configure-apps/runtime-operations)                        | A dictionary of runtime operations |          | No               | Runtime operations for the application.                                                                                                                                                                                                                                                  |

## Root directory

Some of the properties you can define are relative to your app's root directory.
The root defaults to the root of the repository.

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        frontend:
          type: 'nodejs:{{version:nodejs:latest}}'
          # Default behavior of source.root
          source:
            root: "/"`
  }
</DynamicCodeBlock>

That is, if a custom value for `source.root` is not provided in your configuration, the default behavior is equivalent
to the above.

To specify another directory, for example for a [multi-app project](/docs/configure-apps/multi-app),
use the [`source.root` property](/docs/configure-apps/image-properties/source).

## `type`

<Info>
  To install *multiple* runtimes and tools in your application container, use the Upsun composable image.<br />
  If you arrived here from another page, you may want to review the supported `stack` key where `type` was referenced.<br />
  For details, see the list of [supported Nix runtimes](/docs/configure-apps/app-reference/composable-image#upsun-supported-nix-runtimes) that you can define in a composable image `stack`.
</Info>

The `type` defines the base container image used to run the application.
The version is the major (`X`) and sometimes minor (`X.Y`) version numbers,
depending on the service, as in the following table.
Security and other patches are taken care of for you automatically.

Available languages and their supported versions:

| Language           | Type key | Supported versions           |
| ------------------ | -------- | ---------------------------- |
| C#/.Net Core       | `dotnet` | 10.0, 8.0                    |
| Elixir             | `elixir` | 1.19, 1.18, 1.15             |
| Go                 | `golang` | 1.26, 1.25                   |
| Java               | `java`   | 25, 21, 17                   |
| JavaScript/Node.js | `nodejs` | 26, 24, 22                   |
| PHP                | `php`    | 8.5, 8.4, 8.3, 8.2           |
| Python             | `python` | 3.14, 3.13, 3.12, 3.11, 3.10 |
| Ruby               | `ruby`   | 4.0, 3.4, 3.3                |
| Rust               | `rust`   | 1                            |

### Example configuration

These are used in the format `runtime:version`:

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        <APP_NAME>:
          type: 'php:{{version:php:latest}}'`
  }
</DynamicCodeBlock>

## `build`

The only property of the `build` dictionary is `flavor`, which specifies a default set of build tasks to run.
Flavors are language-specific.

See what the build flavor is for your language:

* [Node.js](/docs/languages/nodejs#dependencies)
* [PHP](/docs/languages/php#dependencies)

In all languages, you can also specify a flavor of `none` to take no action at all
(which is the default for any language other than PHP and Node.js).

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        <APP_NAME>:
          source:
            root: "/"
          type: 'nodejs:{{version:nodejs:latest}}'
          build:
            flavor: none`
  }
</DynamicCodeBlock>

## `dependencies`

Installs global dependencies as part of the build process.
They're independent of the code dependencies of your application
and are available in the `PATH` during the build process and in the runtime environment.
They're installed before the `build` hook runs using a package manager for the language.

| Language | Key name              | Package manager                                                                                             |
| -------- | --------------------- | ----------------------------------------------------------------------------------------------------------- |
| PHP      | `php`                 | [Composer](https://getcomposer.org/)                                                                        |
| Python 2 | `python` or `python2` | [Pip 2](https://packaging.python.org/tutorials/installing-packages/)                                        |
| Python 3 | `python3`             | [Pip 3](https://packaging.python.org/tutorials/installing-packages/)                                        |
| Ruby     | `ruby`                | [Bundler](https://bundler.io/)                                                                              |
| Node.js  | `nodejs`              | [npm](https://www.npmjs.com/) (see [how to use yarn](/docs/languages/nodejs#use-yarn-as-a-package-manager)) |

The format for package names and version constraints are defined by the specific package manager.

An example of dependencies in multiple languages:

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        <APP_NAME>:
          type: 'nodejs:{{version:nodejs:latest}}'
          source:
            root: "/"
          dependencies:
            php: # Specify one Composer package per line.
              drush/drush: '8.0.0'
            python2: # Specify one Python 2 package per line.
              behave: '*'
              requests: '*'
            python3: # Specify one Python 3 package per line.
              numpy: '*'
            ruby: # Specify one Bundler package per line.
              sass: '3.4.7'
            nodejs: # Specify one NPM package per line.
              pm2: '^4.5.0'`
  }
</DynamicCodeBlock>

## `runtime`

This applies to PHP only.

The following table lists the various possible modifications to your PHP runtime:

| Name                        | Type                                                       | Language | Description                                                                                             |
| --------------------------- | ---------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `extensions`                | List of `string`s OR [extensions definitions](#extensions) | PHP      | [PHP extensions](/docs/languages/php/extensions) to enable.                                             |
| `disabled_extensions`       | List of `string`s                                          | PHP      | [PHP extensions](/docs/languages/php/extensions) to disable.                                            |
| `request_terminate_timeout` | `integer`                                                  | PHP      | The timeout (in seconds) for serving a single request after which the PHP-FPM worker process is killed. |
| `sizing_hints`              | A [sizing hints definition](#sizing-hints)                 | PHP      | The assumptions for setting the number of workers in your PHP-FPM runtime.                              |
| `xdebug`                    | An Xdebug definition                                       | PHP      | The setting to turn on [Xdebug](/docs/languages/php/xdebug).                                            |

You can also set your [app's runtime timezone](/docs/configure-apps/timezone).

### Extensions

<Info>
  To install multiple runtimes and tools in your application container, use the Upsun composable image.<br />
  If you arrived here from another page and you are using the composable image, you enable and disable extensions by using the `stack.runtimes.extensions`/`stack.runtimes.disabled_extensions` keys.<br />
  For details and an example, see the [`stack`](/docs/configure-apps/app-reference/composable-image#stack) section in the "Composable image" topic.
</Info>

You can enable [PHP extensions](/docs/languages/php/extensions) just with a list of extensions:

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        <APP_NAME>:
          type: 'php:{{version:php:latest}}'
          source:
            root: "/"
          runtime:
            extensions:
              - geoip
              - tidy`
  }
</DynamicCodeBlock>

Alternatively, if you need to include configuration options, use a dictionary for that extension:

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        <APP_NAME>:
          type: 'php:{{version:php:latest}}'
          source:
            root: "/"
          runtime:
            extensions:
              - geoip
              - name: blackfire
                configuration:
                  server_id: <SERVER_ID>
                  server_token: <SERVER_TOKEN>`
  }
</DynamicCodeBlock>

In this case, the `name` property is required.

### Sizing hints

The following table shows the properties that can be set in `sizing_hints`:

| Name              | Type      | Default | Minimum | Description                                    |
| ----------------- | --------- | ------- | ------- | ---------------------------------------------- |
| `request_memory`  | `integer` | 45      | 10      | The average memory consumed per request in MB. |
| `reserved_memory` | `integer` | 70      | 70      | The amount of memory reserved in MB.           |

See more about [PHP-FPM workers and sizing](/docs/languages/php/fpm).

## Resources (CPU, memory, and disk space)

By default, Upsun assigns a container profile and container size to each application and service on the first deployment of a project. <br />

The container *profile* defines and enforces a specific CPU-to-memory ratio. The default container profile for an app or service in a composable image is `HIGH_CPU`.

Use the Upsun CLI or Console to manually adjust the allocated container *size* (CPU and memory resources)—that is, to perform a **vertical‑scaling** action. When you redeploy, the container runs with the CPU‑to‑memory ratio defined by its profile, so it enforces the size you specified.

Related topics:

* For detailed steps for changing the container size, see the [Vertical scaling](/docs/manage-resources/adjust-resources#vertical-scaling) section of the "Resource configuration topic.
* For details about container sizes for each resource allocation strategy (shared CPU, guaranteed CPU, and initial allocation), see the [Advanced: Container profiles](/docs/manage-resources/adjust-resources#advanced-container-profiles) section of the "Resource configuration" topic.
* To learn more about general resource management in Upsun, see the topics in the [Manage resources](/docs/manage-resources) section.

### Downsize a disk

You can reduce the target disk size of an app. Keep in mind:

* Backups created before the downsize are incompatible and cannot be used; you must [create new backups](/docs/environments/backup).
* The downsize will fail if the disk contains more data than the target size.

### Combine single-runtime and composable images

In a [multiple application context](/docs/configure-apps/multi-app),
you can use a mix of single-runtime images
and [composable images](/docs/configure-apps/app-reference/composable-image).

The following sample configuration includes two applications:

* `frontend` – uses a single-runtime image
* `backend` – uses a composable image<br />
  In this app, PHP is the primary runtime and is started automatically (PHP-FPM also starts automatically when PHP is the primary runtime). For details, see the [PHP as a primary runtime](/docs/configure-apps/app-reference/composable-image#php-as-a-primary-runtime) section in the Composable image topic.

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        frontend:
          # this app uses the single-runtime image with a specific node.js runtime
          type: 'nodejs:{{version:nodejs:latest}}'
        backend:
          # this app uses the composable image and specifies two runtimes
          type: "composable:{{version:composable:latest}}"
          stack:
            runtimes:
              - "php@8.4":
                  extensions:
                    - apcu
                    - sodium
                    - xsl
                    - pdo_sqlite
              - "python@3.13"
            packages:
              - "python313Packages.yq" # python package specific`
  }
</DynamicCodeBlock>
