Creating a Static Build
This page explains how to prepare a landscape for export and how to run the export, from the Landscape Config Editor or through the Public API.
Prerequisites
A v0.5 landscape configuration
Static builds require at least schemaVersion: v0.5. The export rejects older configurations, and the Landscape Config Editor offers to migrate a v0.4 configuration with one click. In v0.5 a service lists its ports as plain numbers, and the service that receives the landscape's public traffic names its port under network.landscapeGateway. A landscape with several public services adds a router service with type: router and network.isLandscapeGateway: true that holds the paths.
schemaVersion: v0.5
prepare:
steps:
- name: Install dependencies
command: npm ci
- name: Compile
command: npm run build
run:
web:
image: node:24-slim
plan: 21
network:
ports: [3000]
landscapeGateway:
httpPort: 3000
steps:
- name: Start
command: node dist/server.js
The Landscape Config Editor edits v0.5 configurations, click Edit YAML for anything the form does not show. A v0.5 landscape deploys like any other, so test it before you export it.
Updating CI.yml schema with one click in the UI.
An image on every reactive
In a regular deployment a reactive without an image runs on the workspace's base image. A static build cannot fall back to that image yet. It builds each reactive on top of the image named in its image field, and the export fails for a reactive without one. Pick an image that ships the runtime your start command needs, for example node:24-slim or python:3.13-slim. In the visual editor, select Custom Base Image under Runtime Config in the service settings.
Only copied files reach the image
The image of a reactive holds three things: the base image, the paths its build section copies in, and its start command. Nothing else from the workspace is carried over. In particular:
- Tools installed in the workspace stay there, whether they came through
nix,aptor apreparestep. Their files are not copied, and the workspace's shell environment that puts them on thePATHis not part of the image either. - Files under
/home/user/appthat are not listed undercopy, including dependencies thatprepareinstalled, such asnode_modulesor a virtual environment.
A service that starts fine in the workspace can therefore fail in the artifact with a missing command or module. For every tool and dependency your start command needs, either use a base image that ships it, or produce it in a build step and copy it in. The example in the next section copies dist, node_modules and package.json for a Node application. After the export, deploy the <profile> (static build) profile it leaves in the workspace to check the result before you hand the artifact on.
Registry credentials
For a private target registry, configure the credentials once under Team > Settings > Container Registries. The export uses the entry whose address matches the target repository, and the same entries let it pull private base images. See Using a private registry.
Option A: Configuring new container registry via navigating to Resource Group (Team) settings from the workspace table.
Option B: Configuring new container registry from static build export dialog.
Configuring the build section
Each reactive can carry a build section that says which workspace files go into its image and which commands run before they are copied. Without one the image contains only the base image and the start command.
- UI
- YAML
In the Landscape Config Editor, open the settings of the reactive and switch to the Build tab.
- Optionally set the Context, the directory the steps run in, relative to the workspace root.
- Under Copy Mapping, click Add Path for every path that should be copied into the image. The Source is relative to the context, the Destination is a path inside the image.
- Under Steps, click Add Step for commands that should run before the copy.
- Save the service.
Configuring the build steps for chosen services.
run:
web:
image: node:24-slim
steps:
- command: node dist/server.js
build:
context: .
copy:
- dist:dist
- node_modules:node_modules
- package.json:package.json
steps:
- name: Drop dev dependencies
command: npm prune --omit=dev
- context (optional): the directory the steps run in, relative to the workspace root. Defaults to
.. - copy (optional):
source:destinationentries. The source is relative to the context. A relative destination lands under/home/user/appin the image, where the service'sstepsrun. - steps (optional): commands that run in the context directory, in order, before the paths are copied.
The build steps run after the profile's prepare steps, in the workspace that performs the export, so they can rely on everything prepare installed. Only the copied paths reach the image.
Exporting
- UI
- Public API
- Open Deploy > Landscape Config Editor and select the CI Profile you want to export. Save your changes, the export is available once the profile is saved and valid.
- Click Export as Static Build in the editor header.
- Enter the Target repository, for example
registry.example.com/team-1/shop, and a Tag, for examplev1. - Click Export.
The dialog shows the progress of the export. You can close it, the export keeps running. When it finishes, the dialog shows Static Build Pushed with the artifact reference, and the workspace receives a profile named <profile> (static build) with the exported configuration, so you can deploy the static version right there to verify it.
Exporting landscape as a static build.
POST /api/static-builds starts an export from a workspace or from a Git repository and returns a conversionId. See Public API for authentication.
curl -X POST "https://<your-codesphere-url>/api/static-builds" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": { "workspaceId": 12345 },
"ciFileName": "ci.prod.yml",
"target": {
"repository": "registry.example.com/team-1/shop",
"indexTag": "v1"
}
}'
To export from a Git repository instead, for example from a release pipeline, pass a Git source. The repository is cloned into a temporary workspace of the given team and plan that is deleted after the export:
"source": {
"teamId": 1,
"planId": 21,
"gitUrl": "https://github.com/your-org/shop",
"gitRef": "v1.0.0",
"isPrivateRepo": false
}
ciFileName is optional and defaults to ci.yml. GET /api/static-builds/{conversionId}/events streams the progress as Server-Sent Events. The final event is either converted, with the artifact reference and the digest of every pushed image, or failed with the error.
curl -N "https://<your-codesphere-url>/api/static-builds/<conversionId>/events" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: text/event-stream"
An export can finish with warnings. They point at parts of the landscape that the artifact does not fully capture, for example a reactive without a build section.
A consumer reads a private artifact with the container registry credentials of the resource group (team) that deploys it, not with yours. See Private artifacts.