Publish is the moment a mutable sandbox becomes a frozen, reproducible artifact ready to serve production traffic.
The pipeline
- Sandbox /workspace (mutable; agent or developer is editing here)
- Source snapshot (tarball, sha256-keyed, stored in object storage)
- Builder VM (Firecracker microVM booted from miosa-builder image)
- Build (Dockerfile / Railpack / buildpack / static packager)
- Release (static tarball or dynamic rootfs/OCI image, sha256-keyed)
- Deployment Version (database row pointing at the release)
- Health check (for dynamic; static skips this)
- Promotion (Deployment.active_version_id updated)
The sequence below shows who acts at each step:
```mermaid
sequenceDiagram
participant YC as Your Code
participant M as MIOSA
YC->>M: POST /deployments/:id/publish
M-->>YC: 202 Accepted (build in progress)
M->>M: freeze /workspace → source snapshot
M->>M: boot builder VM
M->>M: compile + package → release artifact
M->>M: create Deployment Version row
M->>M: health check (dynamic only)
M->>M: promote — Deployment.active_version_id updated
M-->>YC: version.state = ready, public_url live You call one endpoint. MIOSA does all of this internally and returns the result when the version is ready.
The publish call
Response shape:
{
"data": {
"deployment": {
"id": "dep_...",
"active_version_id": "ver_...",
"state": "running",
"public_url": "https://smile-dental.workspace.miosa.app"
},
"version": {
"id": "ver_...",
"kind": "static",
"state": "ready",
"artifact_uri": "s3://...",
"artifact_sha256": "...",
"source_sha256": "..."
},
"services": [
{ "id": "svc_...", "type": "static_web", "state": "healthy" }
],
"promoted": true
}
} Source snapshots
Before the builder runs, MIOSA freezes a snapshot of the sandbox’s source. The snapshot is a tarball of /workspace (or whatever output_path you specify), excluding cache directories that don’t need to ship:
included: application code, package manifests, lockfiles, public assets, config
excluded: node_modules, .next/cache, dist (will be rebuilt), .git (unless needed),
__pycache__, build/, target/ The snapshot tarball is uploaded to object storage and sha256-keyed. The version record stores source_sha256 so retries can rebuild from the exact same input without re-snapshotting.
The sandbox keeps running while the build runs. You can keep editing.
Build modes
MIOSA picks a build mode from the source. You can override with build_command if needed.
| Mode | Trigger | What happens |
|---|---|---|
| Dockerfile | Dockerfile exists in output_path | BuildKit (buildctl) builds the image inside the builder VM |
| Railpack-style auto-detect | package.json / requirements.txt / pyproject.toml / go.mod / mix.exs | MIOSA detector picks the right install + build commands |
| Static packager | Only static files in output (no server entrypoint detected) | Files are tarballed and uploaded as a static release |
| Explicit | buildCommand and/or runCommand provided | MIOSA runs those, then packages whatever’s in output_path |
What gets promoted, and when
Static publishes promote as soon as the artifact is uploaded — there’s nothing to health-check.
Dynamic publishes don’t promote until:
- The build succeeded.
- The release rootfs / OCI image was uploaded.
- New Runtime Instances were scheduled on compute hosts.
- Health checks (
GET healthCheckPath) returned 2xx for the configured grace period (default 30s healthy before promotion).
If health checks fail, the previous version stays live and the new version is marked failed. No traffic is sent to the broken release. Your last known good production keeps serving.
Idempotency
Pass Idempotency-Key on every publish. If the same key is sent twice within the retention window, MIOSA returns the original result without re-building. This makes retries safe — useful for shaky network connections and worker queues.
Failure modes
| Failure | What happens | Recovery |
|---|---|---|
| Build command exits non-zero | Version marked failed, log uploaded, production unchanged | Fix in sandbox, publish again |
| Health check never passes | Version marked failed, runtime instances torn down | Fix run command or healthCheckPath, publish again |
| Source snapshot fails | Publish returns 5xx immediately, no version row created | Retry the request |
| Static build exceeds artifact size limit | Version marked failed | Reduce assets or contact support to raise limit |
| Two publishes race for the same deployment | Second one waits on the advisory lock; both eventually succeed in order | None — handled by Engine.OperationLocks |
See also
- Versions — what publish produces
- Releases — the artifact itself
- Runtime Instances — for dynamic deploys
- Rollback — when health checks pass but the app turns out broken