tcb deploy
Read cloudbaserc.json from the project root and roll out functions, static hosting, gateway routes, and database migrations in dependency order, without calling each single-resource command.
tcb deploy has supported declarative deployment since v3.8.0. From v3.9.0 it only deploys and never builds, and no longer accepts positional arguments or app-specific options (tcb deploy <serviceName>, --framework, --build-command, --output-dir fail with INVALID_PARAM); use tcb app deploy for cloud builds.
Usage
tcb deploy [options]
Parameters
| Parameter | Required | Description | Default |
|---|---|---|---|
-e, --env-id <envId> | No | Environment ID, highest precedence | envId in the configuration |
--mode <mode> | No | Apply envOverrides.<mode> and .env.<mode> | — |
--only <types> | No | Deploy only the given resource types, comma-separated | All |
--skip <types> | No | Skip the given resource types, comma-separated | — |
--dry-run | No | Print the change plan without deploying | false |
--yes | No | Overwrite existing functions without asking | false |
--concurrency <n> | No | Concurrency within a resource type, at most 20 | 5 |
--continue-on-error | No | Keep deploying the other resources after one fails | false |
Valid types for --only / --skip: database / functions / app / hosting / gateway.
Examples
# Deploy every resource
tcb deploy
# Print the change plan only
tcb deploy --dry-run
# Functions only
tcb deploy --only=functions
# Static hosting and gateway only
tcb deploy --only=hosting,gateway
# Skip the gateway
tcb deploy --skip=gateway
# Skip app and let tcb app deploy build it in the cloud
tcb deploy --skip app
# Specific environment, no overwrite confirmation
tcb deploy --env-id=xxx --yes
# Apply the production overrides
tcb deploy --mode=production
# Three concurrent resources of the same type
tcb deploy --concurrency 3
# Keep going when one resource fails
tcb deploy --continue-on-error
Workflow
The standard path from zero to production: initialise the configuration, validate it, build locally, preview the changes, then deploy.
| Step | Command | Purpose | Done when |
|---|---|---|---|
| 1 Initialise | tcb config init | Detects functions, frameworks, and static directories, writes cloudbaserc.json | The project has a valid configuration |
| 2 Validate | tcb validate | Checks the schema version, envId, resource directories, and references | Exit code 0 with a resource summary |
| 3 Build locally | tcb app build | Builds app and hosting[] output into their outputDir; only needed for entries with buildCommand, pure static sites can skip it | Output exists in outputDir |
| 4 Preview | tcb deploy --dry-run | Prints field-level differences (from → to) and the database migration plan | The plan matches expectations |
| 5 Deploy | tcb deploy | Rolls out in database → functions → app → hosting → gateway order, uploading output only | Deployment succeeds |
Options
--dry-run
Print the change plan without deploying:
tcb deploy --dry-run
The output covers field-level differences (from → to) and the database migration plan.
--only / --skip
tcb deploy --only=functions # functions only
tcb deploy --only=hosting,gateway # static hosting and gateway only
tcb deploy --skip=gateway # skip the gateway
tcb deploy --skip app # skip app (pair with tcb app deploy for cloud builds)
Only the five comma-separated resource types are accepted; invalid values fail instead of being ignored:
tcb deploy --only fn # ✗ fn is not a valid resource type
tcb deploy --only "functions hosting" # ✗ space-separated, use commas
tcb deploy --only functions,hosting # ✓
--mode / --env-id
tcb deploy --mode=production # apply envOverrides.production + .env.production
tcb deploy --env-id=xxx # specific environment (highest precedence)
--concurrency
Defaults to 5. Instances of the same type deploy in parallel; resource types still run serially in database → functions → app → hosting → gateway order, so dependencies hold.
tcb deploy --concurrency 3 # up to 3 concurrent functions or hosting sites
- Applies only between consecutive instances of the same type (several hosting sites, several functions); function-to-hosting and hosting-to-gateway transitions always run serially
- Capped at
20to avoid overloading the backend API
--continue-on-error
Default is fail-fast: the first failed resource stops the rest and the process exits non-zero, which CI/CD can detect. --continue-on-error runs every resource first and reports the failures at the end:
tcb deploy --continue-on-error # keep deploying the other resources
databasealways stops the deployment when it fails, with or without this flag — later resources may depend on the newly created schema.
Behaviour
| Dimension | tcb deploy | tcb fn deploy / tcb hosting deploy and friends |
|---|---|---|
| Configuration source | One cloudbaserc.json declares every resource | Each command takes its own arguments |
| Orchestration | database → functions → app → hosting → gateway, sorted automatically | Single resource |
| Dependencies | Functions wait for a new schema (database first), the gateway waits for functions and hosting | Not aware |
| Idempotency | Checks cloud existence, runs on every deploy | Full run every time |
| Overwrite confirmation | Asks before updating an existing function (--yes skips) | --force |
Overwrite confirmation: existing functions (update path) ask before being overwritten, --yes skips the prompt, interactive mode confirms item by item, and without any confirmation channel the CLI conservatively skips them instead of overwriting production. The semantics match tcb fn deploy --force.
Build and deploy separation
tcb deploy deploys only; it never builds or installs dependencies.
| Resource | Build behaviour during tcb deploy | Since |
|---|---|---|
hosting[] | No build, no dependency install, uploads outputDir directly | v3.8.2 |
app | No cloud build, uploads the output and writes a deployment record | v3.9.0 |
functions[] | Still follows buildStrategy (zip / cloud / local / image) | — |
When buildCommand is configured but the output directory is missing or empty, the deploy fails with BUILD_OUTPUT_NOT_FOUND and asks you to run tcb app build first:
tcb app build # build app and hosting[] output into their outputDir
tcb deploy # upload the output and roll out the rest
To build a frontend app in the cloud, skip it with --skip app and hand it to tcb app deploy:
tcb deploy --skip app # hosting + functions + gateway, app excluded
tcb app deploy <serviceName> # deploy the app alone with a cloud build
Configuration example
Minimal cloudbaserc.json:
{
"envId": "your-env-id",
"functions": [
{ "name": "pay-common", "type": "Event", "handler": "index.main" }
],
"hosting": [
{
"name": "web",
"root": "web",
"framework": "vite",
"outputDir": "dist",
"deployPath": "/web"
}
],
"gateway": {
"routes": [
{ "path": "/api", "target": "function:pay-common" },
{ "path": "/web", "target": "hosting:web" }
]
}
}
Matching directory layout:
project/
├── cloudbaserc.json
├── functions/
│ └── pay-common/
│ └── index.js
└── web/
└── dist/ # build output from tcb app build
The full directory convention is in Project layout; database migrations default to cloudbase/migrations/.
Resources
| Resource | Field | Key points | Reference |
|---|---|---|---|
| Database migrations | database | postgresql only; files named 14-digit-timestamp_name.sql in cloudbase/migrations/ by default; a conflict stops the deployment | Config file - database |
| Functions | functions | Event and HTTP types; zip package or image deployment (buildStrategy); HTTP functions support public anonymous access and gatewayPath routing | Function configuration · Deploy functions |
| Static hosting app | app | No build, uploads outputDir and writes a deployment record; outputDir is inferred when missing, pure static sites fall back to the project root; use tcb app deploy for cloud builds | App deployment |
| Static hosting | hosting | Multiple sites as an array; build locally with tcb app build, tcb deploy uploads the output only | Static website hosting · tcb app build |
| Gateway routes | gateway.routes | target is function:<name> or hosting:<name>; pathRewrite is generated automatically | Config file - gateway |
| Environment overrides | envOverrides | Merged by --mode | Configuration file |
A route target: function:<name> accepts both function types: HTTP functions become WEB_SCF routes, Event functions become SCF routes (the gateway wraps the HTTP request into an event). The CLI queries the function detail to decide.
Database migrations
SQL files in database.migrations are applied to PostgreSQL in order:
| Dimension | Description |
|---|---|
| Supported type | type: postgresql only (type: nosql is passed through, not orchestrated) |
| Migration files | Named 14-digit-timestamp_lowercase-name.sql (for example 20260101120000_init.sql), default directory cloudbase/migrations/ |
Plan (--dry-run) | Aggregated into one change item: pending → create |
| Conflict handling | A migration with the same name already in the target database stops the deployment |
| Failure policy | database always stops the deployment, even with --continue-on-error, because later resources may need the new schema |
database runs first in the order, so a failure skips every later resource. Confirm the plan with tcb deploy --dry-run first.
Project layout
Recommended layout:
vibe-app/
├── cloudbaserc.json # declarative configuration (the contract)
├── .env # secrets (not in Git; .env.<mode> with --mode <mode>)
├── .env.example # secret template (in Git)
├── cloudbase/migrations/ # database migrations (SQL, default directory)
│ ├── 20260101120000_init.sql
│ └── 20260102150000_add_users.sql
├── functions/ # function code (functionRoot defaults to ./functions)
│ ├── task-runner/ # Event function: exports.main(event, context)
│ └── api-server/ # HTTP function: needs a scf_bootstrap script
├── web/ # frontend code (hosting[].root)
└── Dockerfile # for HTTP image deployment (optional, inside the function directory)
Path resolution:
| Resource | Field | Default / rule |
|---|---|---|
| Migration directory | database.migrations | cloudbase/migrations/ relative to the project |
| Function root | functionRoot | functions/ |
| Function code directory | dir / functionRoot + name | Explicit dir → {cwd}/{dir} (independent of functionRoot); otherwise {cwd}/{functionRoot}/{name} |
| Frontend site | hosting[].root | Relative to the project directory |
FAQ
1. Which directory is uploaded when app.outputDir is missing?
tcb deploy does not build; outputDir decides where to upload from, and app follows the same rule as hosting[]:
outputDir | Result |
|---|---|
A non-empty string ("." counts) | Used as-is, no inference |
Missing / "" / whitespace only | Inferred: explicit buildCommand → dist; a build command derived from framework or package.json → the framework output directory (falls back to dist); no build command (pure static) → root |
| Not a string (array, number, …) | Fails with INVALID_PARAM |
A pure static entry landing on the project root is legal; the terminal prints the actual upload directory and a hint:
[my-app] 上传产物:项目根(/path/to/project)
纯静态站点可保持此配置;前端项目建议用 app.outputDir 指定产物目录(如 dist),并先执行 tcb app build
Frontend projects should set outputDir explicitly, otherwise the sources (including .env) are uploaded as output:
{
"app": {
"serviceName": "my-app",
"outputDir": "dist"
}
}
A missing or empty output directory fails at deploy time with BUILD_OUTPUT_NOT_FOUND; under --dry-run the resource is only marked as not ready.
tcb app deployresolves differently:--output-dir>app.outputDir> auto-detection > prompt / default (./distwith a build step,./without).
2. gateway.routes validation fails (should NOT have additional properties)
cloudbaserc.json rejects unknown fields. For example cdnType is not a valid route field and must be removed; control CDN access with accessType (DIRECT / CDN / CUSTOM / EO):
{ "path": "/web", "target": "hosting:web", "accessType": "DIRECT" }
3. Dependency installation for HTTP functions
| Function type | Runtime | Dependency installation |
|---|---|---|
| Event | Any | Installed online in the cloud (default) |
| HTTP | Node.js | Installed online in the cloud (default) |
| HTTP | Non-Node.js (Python / Php / Java / Go) | Must be installed locally and shipped with the code package |
For HTTP non-Node.js functions install dependencies locally first (for example pip install into the function directory).
4. Are existing functions overwritten?
Existing functions ask for confirmation; --yes skips it.
5. Domain-level fields do not apply to routes on an existing domain
certId / protocol / accessType are domain-level fields shared by every route on the domain. When a route is created on an existing domain these fields do not override the current values (a domain bound to HTTP_AND_HTTPS ignores protocol: "HTTPS"), which protects other services on the same domain. They only take effect when the domain is first created.
6. Gateway route idempotency
Gateway routes converge idempotently (create / update / skip):
- Route missing → create
- Route exists and the explicitly declared fields match → skip
- Route exists but an explicitly declared field differs → update (calls
modifyHttpServiceRoute)
Only explicitly declared fields are compared (enableAuth / enablePathTransmission only when configured, qpsPolicy / pathRewrite only when present locally); undeclared fields never overwrite the cloud configuration. A duplicate path is not an error (unlike the INVALID_PARAM of the imperative tcb routes add). Field definitions: Config file - gateway.
Related Commands
- Get started: install the CLI, log in, generate
cloudbaserc.json - Validate before deploy
- Initialise configuration
- Configuration file: fields and dynamic variables
- HTTP gateway route management
- Function configuration