How to use multiple workshops in a project

A project may require different toolchains for different components, such as a Go backend and a Node.js frontend. Instead of putting everything into a single workshop definition, you can define multiple workshops in the same project directory. Each workshop is an independent environment with its own base image, SDKs, and actions; at the same time, the workshops share a single project directory mounted at /project/.

Set up definitions

When a project uses multiple workshops, store their definitions in the .workshop/ subdirectory instead of a single workshop.yaml in the project root. Each file must be named after its workshop, so the name field matches the file name (without the .yaml extension).

Here is a project layout with two workshop definitions and a shared in-project SDK:

my-project/
├── .workshop/
│   ├── frontend.yaml
│   ├── backend.yaml
│   └── common-tools/
│       └── sdk.yaml
├── web/
└── api/

The frontend workshop uses the node SDK for the browser-facing part of the project:

.workshop/frontend.yaml
name: frontend
base: ubuntu@24.04
sdks:
  - name: node
    channel: 24
actions:
  build: |
    npm run build

The backend workshop uses the go SDK for the server-side code:

.workshop/backend.yaml
name: backend
base: ubuntu@22.04
sdks:
  - name: go
    channel: 1.26
actions:
  test: |
    go test ./...

Each workshop can use a different base image, a different set of SDKs, and its own actions, all while sharing the project directory.

What’s more, you can share in-project SDKs across workshops, as described in a section below.

Note

You cannot mix a root-level workshop.yaml with files in .workshop/. If Workshop finds both, it reports an error.

Launch and manage workshops

Launch both workshops at once:

$ workshop launch frontend backend

When a project has multiple workshops, the workshop name is required in every command; you cannot omit it as you would with a single-workshop project.

Check the status of both workshops:

$ workshop list

  WORKSHOP  STATUS  NOTES
  frontend  Ready   -
  backend   Ready   -

Run an action in a specific workshop:

$ workshop run frontend -- build
$ workshop run backend -- test

Shell into one of the workshops:

$ workshop shell backend

Execute a one-off command:

$ workshop exec frontend -- node --version

Stop and start workshops independently:

$ workshop stop frontend
$ workshop start frontend

Or stop both at once:

$ workshop stop frontend backend

To see the status of workshops in the current project, use the workshop list command without arguments:

$ workshop list

  WORKSHOP  STATUS  NOTES
  frontend  Ready   -
  backend   Ready   -

To see the status of workshops across all projects on the system, use the --global flag:

$ workshop list --global

  PROJECT                   WORKSHOP  STATUS  NOTES
  /home/user/my-project     frontend  Ready   -
  /home/user/my-project     backend   Ready   -
  /home/user/other-project  dev       Ready   -

When you no longer need the workshops, remove them:

$ workshop remove frontend backend

Share in-project tools

If multiple workshops need the same custom tooling, define an in-project SDK rather than duplicating hooks or configuration. In-project SDKs are stored in subdirectories of .workshop/ and referenced with the project- prefix.

Both workshops can then include it:

.workshop/frontend.yaml
name: frontend
base: ubuntu@24.04
sdks:
  - name: node
    channel: 24
  - name: project-common-tools
.workshop/backend.yaml
name: backend
base: ubuntu@22.04
sdks:
  - name: go
    channel: 1.26
  - name: project-common-tools

After adding the SDK references, refresh the workshops to pick up the change:

$ workshop refresh frontend backend

Cross-workshop networking

You cannot connect a plug in one workshop to a slot in another; workshop connect rejects such attempts. However, all workshops on the same machine share a common host, and the tunnel interface can bridge through it.

The idea is to compose two independent tunnels: one that exposes a service from the backend workshop to the host, and another that lets the frontend workshop reach that host port. This is different from a regular intraworkshop connection, where a single tunnel links a plug to a slot inside the same workshop. Here, the host sits in the middle, and each workshop configures its own half of the bridge.

The backend workshop exposes its API on the host by pairing a system plug with a regular SDK slot:

.workshop/backend.yaml
name: backend
base: ubuntu@22.04
sdks:
  - name: go
    channel: 1.26
    slots:
      api:
        interface: tunnel
        endpoint: localhost:8080    # service inside the workshop
  - name: system
    plugs:
      api:
        interface: tunnel
        endpoint: localhost:8080    # port on the host

The frontend workshop reaches the host port by pairing a regular SDK plug with a system slot:

.workshop/frontend.yaml
name: frontend
base: ubuntu@24.04
sdks:
  - name: node
    channel: 24
    plugs:
      api:
        interface: tunnel
        endpoint: localhost:8080    # where the client connects
  - name: system
    slots:
      api:
        interface: tunnel
        endpoint: localhost:8080    # host-side port (bridged from backend)

Launch both workshops. The backend tunnel auto-connects because its plug is on the system SDK with a matching name, but the frontend tunnel requires a manual step:

$ workshop launch frontend backend
$ workshop connect frontend/node:api

Verify the connection:

$ workshop connections frontend

  INTERFACE  PLUG                   SLOT                   NOTES
  tunnel     frontend/node:api      frontend/system:api    manual

After this, any service listening on port 8080 inside the backend workshop is reachable at localhost:8080 from within the frontend workshop.

Note

The host port must be free before launching the backend workshop, or the tunnel will fail to activate. If you need several cross-workshop tunnels, use a different port for each. See How to forward ports with tunneling for tunnel basics and troubleshooting.

See also

Explanation:

How-to guides:

Reference: