8.6 Building, bundling, and deploying (rs2 deploy)

Deploying a custom service is a two-stage idea: upload the code (it's stored content-addressed and immutable), then mount it by reference. This section covers getting the bytes onto the node; 8.7 covers mounting and versioning.

JavaScript: bundle then upload

Your source can import dependencies, but the runtime won't resolve modules at runtime (8.3) — so you bundle to a single ES module first. rs2 deploy --bundle does both steps:

rs2 deploy service.ts --name my-svc --bundle

--bundle runs npx esbuild service.ts --bundle --format=esm --platform=browser (the same settings the compat layer is tested against), then uploads the result. npm deps resolve at build time; native addons fail there (the right place to find out). Node.js must be on PATH for this.

Without --bundle, deploy uploads the file as-is (use it when you've already bundled).

WebAssembly: build then upload

cargo build --target wasm32-wasip2 --release
rs2 deploy target/wasm32-wasip2/release/my_svc.wasm --name my-svc

The CLI detects the type by content: .js/.mjs deploy as JS bundles; \0asm files as components.

Targeting a server

rs2 deploy service.ts --name my-svc --bundle `
  --server http://127.0.0.1:3100/services `
  --token  $adminToken

--server defaults to http://127.0.0.1:3100/services; --token adds a bearer header for a protected services mount (the deploy goes through the self-config API, so it's gated by that mount's write access — operators only, 5.0).

The raw HTTP equivalent

rs2 deploy is a convenience over the services code store (Part 10). Under the hood it's:

POST /services/code/my-svc/         Content-Type: application/javascript | application/wasm
→ 201 + Location + { name, version, ref, validated }

The response gives you the immutable refcode:my-svc@<version> — which you'll use to mount it.

You can attach an optional discovery manifest at deploy time with the X-RS2-Manifest header. It declares inputSchema, outputSchema, effect and media types (and optionally a store pattern), so a custom mount appears in the agent surface and OpenAPI with a useful contract instead of as an opaque action. The manifest is stored beside the bundle but does not change its content hash. See 8.11 for the shape.

The compile smoke test

On upload, the server runs a compile smoke test when the matching engine is in its build: a broken bundle is rejected with 502 contract_violation (with the JS exception or compile error included), so bad code never becomes a deployable version. Identical bytes always produce the identical version (content-addressed).

Validate before you ship

rs2 test <projectDir> checks the manifest and component locally before you deploy — a faster loop than discovering problems at upload. Use it as your pre-deploy gate.

With the bytes uploaded and a ref in hand, the next section mounts the service and explains versioning and rollback.


Previous: 8.5 Capability grants · Manual home · Next: 8.7 Versioning, rollback, mounting →