--> -->

Platform.sh supports building multiple applications per project (for example RESTful web services with a front-end, or a main website and a blog). For resource allocation reasons, however, that is not supported on Standard plan.

Project structure 

There are multiple ways to structure such a project, depending on the way your source code is organized and what your goal is. All of these approaches may be used within a single project simultaneously, although it is often easier to maintain if you settle on just one approach for a given project.

Multi-app

Discrete code bases 

If your project consists of a discrete code base for each application, the most straightforward approach is to put both code bases into a single project repository in separate directories. Each will have its own .platform.app.yaml file, which will define how that particular application gets built, using the code in that directory.

For example, if you have a Drupal back end with an AngularJS front end you could organize the repository like this:

.git/
.platform/
drupal/
  .platform.app.yaml
  ...
angular/
  .platform.app.yaml

Each .platform.app.yaml file will define a single application container, and build code in that directory. The .platform directory is outside of all of them and still defines additional services you require, as well as routes.

Note that disk paths in the .platform.app.yaml file are relative to the directory where that file lives by default.

This is the recommended approach for most configurations.

Explicit source.root 

As an alternative, you may specify a source.root key in a .platform.app.yaml file to override the “application root is where the file is” logic. The .platform.app.yaml file may then live anywhere in the repository but use code from another directory. Two separate .platform.app.yaml files may refer to the same directory if desired.

For example:

# .platform.app.yaml

source:
    root: restapp
.platform/
main/
    .platform.app.yaml
.platform.app.yaml
restapp/
    # Your code here

In this case, the .platform.app.yaml file in main does not specify a source.root, and so will be built from the code in main. The top-level .platform.app.yaml includes the YAML fragment above. It will get built using the code in restapp, as if it were in that directory.

Note that disk parameters in the .platform.app.yaml file will be relative to the source.root directory if specified. The source.root path is relative to the repository root.

The primary use case for this configuration is if the source code is pulled in as a Git submodule or downloaded during the build phase.

applications.yaml 

It is possible to define an application in a .platform/applications.yaml file in addition to discrete .platform.app.yaml files. The syntax is nearly identical, but the source.root key is required. The applications.yaml file is then a YAML array of application definitions.

For example, the following .platform/applications.yaml file defines three applications:

# .platform/applications.yaml
-   name: api
    type: golang:1.14
    source:
        root: apiapp
    hooks:
        build: |
            go build -o bin/app
    web:
        upstream:
            socket_family: tcp
            protocol: http
        commands:
            start: ./bin/app
        locations:
            /:
                allow: false
                passthru: true

-   name: main
    type: "php:7.4"
    source:
        root: mainapp
    web:
        locations:
            "/":
                root: "web"
                passthru: "/index.php"

-   name: admin
    type: "php:7.4"
    size: S
    source:
        root: mainapp
    web:
        locations:
            "/":
                root: "web"
                passthru: "/admin.php"

In this example, the apiapp directory will get built as a Go application while the mainapp directory will get built as two separate PHP applications, even though none of those directories has a .platform.app.yaml file. The two PHP applications will use the same source code, but have different front controllers for the admin and main applications. The admin instance will also be fixed at an S size container, while main will scale freely.

The primary use case for this configuration is defining multiple applications with different configuration off of the same source code, or when the source code is downloaded during the build phase.

Submodules 

Platform.sh supports Git submodules, so each application can be in a separate repository. However, there is currently a notable limitation: the .platform.app.yaml files must be in the top-level repository. That means the project must be structured like this:

.git/
.platform/
    routes.yaml
    services.yaml
app1/
    .platform.app.yaml
    app1-submodule/
        index.php
app2/
    .platform.app.yaml
    app2-submodule/
        index.php

This puts your applications’ files at a different path relative to your .platform.app.yaml files. The recommended way to handle that is to specify a source.root key in the .platform.app.yaml file and have it reference the submodule directory.

Multi-app Routes 

Every application, however it is defined, must have a unique name property. The routes.yaml file may then refer to that application by name as an upstream for whatever route is appropriate.

For example, assuming this configuration from above:

.git/
.platform/
drupal/
  .platform.app.yaml
  ...
angular/
  .platform.app.yaml

The .platform/routes.yaml file can be structured like this:

"https://backend.{default}/":
    type: upstream
    upstream: "drupal:http"
"https://{default}/":
    type: upstream
    upstream: "angular:http"

(This assumes your Drupal application is named drupal and your Angular front-end is named angular.)

Assuming a domain name of example.com, that will result in:

  • https://backend.example.com/ being served by the Drupal instance.
  • https://example.com/ being served by the AngularJS instance.

There is no requirement that an application be web-accessible. If it is not specified in routes.yaml then it will not be web-accessible at all. However, if you are building a non-routable application off of the same code base as another application, you should probably consider defining it as a worker instead. The net result is the same but it is much easier to manage.

Relationships 

In a multi-app configuration, applications by default cannot access each other. However, they may declare a relationships block entry that references another application rather than a service. In that case the endpoint is http.

However, be aware that circular relationships are not supported. That is, application A cannot have a relationship to application B if application B also has a relationship to application A. Such circular relationships are usually a sign that the applications should be coordinating through a shared data store, like a database, RabbitMQ server, or similar.