--- name: zerops-import description: Create Zerops projects and services with import YAML, including managed databases, storage, scaling and environment references. Use when provisioning infrastructure for a new app or adding services to an existing project. --- # Import projects and services ## 1. Establish the target Use `zerops-setup` to install and authenticate zcli, choose the organization and region, and record the target IDs. Require zcli v1.1.3 or newer; verify with `zcli version`. Do not assume the npm package contains browser login. Follow the verified installation route in `zerops-setup` and use browser login first; `ZEROPS_TOKEN` is for CI/headless use. Never request tokens in chat, print them, or read the CLI credential store. Choose one operation: - **New project:** write `project` plus `services`; pass the organization ID. - **Existing project:** write only `services`; pass the existing project ID. Import describes infrastructure. Write application build/run configuration with `zerops-yaml` and deploy local source with `zerops-deploy`. Importing an empty runtime does not deploy an application. No VPN, SSH or Zerops container is needed for these CLI commands, including from a cloud sandbox. Read [examples.md](references/examples.md) for app + PostgreSQL, app + Valkey + Object Storage, or a static site. Read [managed-services.md](references/managed-services.md) for the chosen managed service's type, versions, connection variables and HA notes. ## 2. Check the current contract Use the [live import JSON Schema](https://api.app-prg1.zerops.io/api/rest/public/settings/import-project-yaml-json-schema.json) for accepted types, versions, fields and type-specific constraints. The public [OpenAPI](https://api.app-prg1.zerops.io/api/rest/public/swagger/openapi.yml) documents this unauthenticated schema endpoint. Check the schema again when authoring an import; a listed version is not a promise of deployment success. The [import documentation](https://docs.zerops.io/references/import) includes older examples. The schema checked on 2026-10-21 deprecates `mode`, `envVariables` and `envSecrets` at import level. Prefer managed type variants and `vault` below; `run.envVariables` in `zerops.yaml` remains the application mapping mechanism. Do not copy a generic example's storage or scaling fields onto every service. ## 3. Define the project and services For a new project, set `project.name`. Optional fields include `description`, `tags` (a list of strings), `corePackage: LIGHT` or `SERIOUS`, and `vault`. Project names may repeat, so retain IDs after creation. The default core package is `LIGHT`; choose the package deliberately because a later core upgrade cannot be downgraded. If placement matters, check `project.location` against the live schema; location is separate from the login API region. Define at least one item under `services`: | Field | Authoring rule | | --- | --- | | `hostname` | Required, unique in the project; at most 25 lowercase ASCII letters or digits. Do not use hyphens or underscores. | | `type` | Required. Use a schema-listed runtime such as `ubuntu/nodejs@24`, a managed variant such as `postgresql:single@18`, or an unversioned type such as `object-storage`. | | `mode` | Legacy docs use `HA` / `NON_HA`. The current schema marks this field deprecated: select `:ha` / `:single` in a managed type instead. Runtime redundancy uses container counts. | | `priority` | Integer; larger numbers create services earlier. Give dependencies a higher value, e.g. `10` for a database and `1` for the app. This orders creation, not application readiness. | | `vault` | Map values directly, or use `{value: ..., sensitive: true}` for a secret. Use project vault for shared values and service vault for values owned by one service. | | `envSecrets` | Legacy map of string values stored as sensitive/encrypted configuration. Document or migrate existing uses to `vault` with `sensitive: true`; do not author new secret literals here. `dotEnvSecrets` is the older multiline alternative. | | `enableSubdomainAccess` | Boolean, default false; request public access on a web runtime when a Zerops public URL is wanted. Complete [Activate and verify public access](../zerops-deploy/SKILL.md#activate-and-verify-public-access) in `zerops-deploy`; configure its HTTP port with `zerops-yaml` and production domains with `zerops-operate`. | | `buildFromGit` | Optional one-time build from a public GitHub/GitLab repository URL without a trailing `.git`. It does not configure continuous Git integration. For local/private source, omit it and use `zerops-deploy`. | | `zeropsSetup` / `zeropsYaml` | Select a setup and optionally supply the pipeline configuration in the import. Keep its content aligned with `zerops-yaml`; do not duplicate a repository pipeline without a reason. | Leave `override` absent for creation. `override: true` can redeploy an existing same-hostname runtime; it is not an idempotency switch for arbitrary services. ### Scaling and storage On runtimes, use `minContainers` / `maxContainers` for horizontal scaling and `verticalAutoscaling` for per-container resource settings: - Set `minCpu` / `maxCpu`, `minRam` / `maxRam`, `minDisk` / `maxDisk` for bounds, or `cpu`, `ram`, `disk` for fixed resources. CPU is thread count; RAM/disk use GB. - Set `cpuMode: SHARED` or `DEDICATED` only after choosing the intended resource policy. Other supported tuning keys include `startCpuCoreCount`, `minFreeCpuCores`, `minFreeCpuPercent`, `minFreeRamGB`, `minFreeRamPercent`, and `swapEnabled`; check the selected type's schema constraints before using them. - Keep minimums no larger than maximums. Do not assume one global resource limit across runtimes, databases and storage. - For managed databases, choose their topology and, where supported, `profile` using the catalogue. Do not copy runtime container counts to managed services. For Object Storage, use `type: object-storage`, `objectStorageSize` in GB, and `objectStoragePolicy: private` unless public access is intended. Other schema policies are `public-read`, `public-objects-read`, `public-write`, `public-read-write`, and `custom`. For a custom policy, use `objectStoragePolicy: custom` with `objectStorageRawPolicy` containing JSON as a YAML string; its bucket placeholder is `{{ .BucketName }}`. Do not attach runtime CPU/RAM/disk scaling or container counts to Object Storage. ## 4. Generate secrets and reference dependencies Put `#yamlPreprocessor=on` on the **first line** when using generators. Generate new secrets during import rather than storing their resolved values in a file: ```yaml #yamlPreprocessor=on services: - hostname: app type: ubuntu/nodejs@24 vault: APP_SECRET_VALUE: value: <@generateRandomString(<32>)> sensitive: true ``` The [preprocessor reference](https://docs.zerops.io/references/import-yaml/pre-processor) defines the exact syntax. Useful forms include: - `<@generateRandomString(<32>)>` generates a string; supported length is 1–1024. - `<@generateRandomStringVar(, <32>)>` generates and stores an internal preprocessor variable; a later `<@getVar(sharedSecret)>` reuses it. - `<@setVar(, )>` stores a value for a later `<@getVar(name)>`. These functions return strings and run before YAML processing; generated values are not regenerated on each application start. Read the preprocessor reference for byte/int/key-pair generators and escaping, especially for backslashes and reserved `<`, `>`, `|` characters. Do not confuse preprocessor variables with runtime `${...}` references. In the app's `zerops.yaml`, map each consumed value explicitly under `run.envVariables`, using `${hostname_variableName}` for another service: ```yaml zerops: - setup: app run: envVariables: DATABASE_URL: ${db_connectionString} APP_SECRET: ${APP_SECRET_VALUE} ``` This is a mapping fragment, not a complete application pipeline. Managed services generate their own credentials: do not set `db_password` or invent credentials. Read the exact case-sensitive names in the catalogue. Explicit references work with service isolation; do not assume sibling variables are automatically injected. Use a different app key and vault key to avoid a self-reference such as `APP_SECRET: ${APP_SECRET}`. Keep secrets out of frontend build output. ## 5. Import non-interactively Save a separate import file, e.g. `zerops-import.yaml`, rather than confusing it with the application's `zerops.yaml`. Validate YAML and its fields against the current import schema before applying it. Keep `${...}` and `<@...>` literal when writing from a shell (use a quoted heredoc). Do not commit resolved secrets. For a **new project**, set `ORG_ID` to the chosen organization ID and run: ```sh zcli project project-import ./zerops-import.yaml --org-id "$ORG_ID" ``` For **additional services in an existing project**, remove the `project` block, set `PROJECT_ID` to the verified target ID, and run: ```sh zcli project service-import ./zerops-import.yaml --project-id "$PROJECT_ID" ``` Run each import directly, as shown, and retain its exit status. Do not pipe it to `tail` or another command unless the shell has `set -o pipefail`; otherwise the last command can hide an import failure. If saving output, redirect it to a log and capture the import status before reading that log. Both accept `-` instead of a file path for stdin. Files are relative to the shell working directory; use an absolute path when uncertain. Only `project-import` accepts `--working-dir`. v1.1.3 rejects empty input and input over 102400 bytes. Supply the explicit ID flags to avoid organization/project selection prompts. If an installed version differs, inspect `zcli project project-import --help` or `zcli project service-import --help`; do not invent flags. ## 6. Wait, check and hand off Keep the import command running: both commands wait for all returned service processes and then report `project imported` or `service(s) imported`. There is no import no-wait or timeout flag in v1.1.3. An interrupted command can exit zero; that alone is not evidence of completion. After completion, inspect IDs, organization and statuses without dumping env: ```sh zcli project list zcli service list --project-id "$PROJECT_ID" ``` For a new project, identify its ID from the project table before listing services; do not match only a possibly duplicated name. Compare project IDs before and after creation if needed. Check that every requested hostname exists and inspect its status. Use `zerops-operate` for failures. Import exit 0 and completed service creation establish provisioning, not a live application. Follow `zerops-deploy` for the first application deployment and its [public-access activation and URL check](../zerops-deploy/SKILL.md#activate-and-verify-public-access); deployment success requires both push exit 0 and the URL check. A provisioned runtime awaiting code is not yet a working website. On failure or interruption, inspect existing projects/services before retrying: a partial import may already have created resources. Do not repeatedly rerun a new-project import or add `override` to hide a collision. API errors may contain server metadata; report only relevant non-secret error details. Never use an env dump as a readiness check. Report IDs, created hostnames, observed statuses and the remaining deploy step; do not report generated credentials. ## Sources Fields and limits above were checked against the linked live schema and public import/preprocessor docs on 2026-10-21. CLI behavior was checked against zcli v1.1.3 source: [project import](https://github.com/zeropsio/zcli/blob/v1.1.3/src/cmd/projectImport.go), [service import](https://github.com/zeropsio/zcli/blob/v1.1.3/src/cmd/projectServiceImport.go), [input reader](https://github.com/zeropsio/zcli/blob/v1.1.3/src/yamlReader/importYaml.go), and [process waiter](https://github.com/zeropsio/zcli/blob/v1.1.3/src/uxHelpers/spinner.go).