Documentation Index
Fetch the complete documentation index at: https://docs.tesslate.com/llms.txt
Use this file to discover all available pages before exploring further.

Overview
In OpenSail, a deployment target is a first-class node on the Architecture Panel canvas. You draw a dashed orange edge from a container node (frontend, backend, worker) to a target node, and the orchestrator handles the rest: build, package, authenticate with the provider, and stream status back. The same container can fan out to many targets, each with its own environment, env-var overrides, deployment history, and rollback.22 external targets
A/B variants
Per-target environment
production, staging, preview on the target header. Env-var merge runs in four layers.Independent rollback
What a target owns
EachDeploymentTarget row tracks:
- Provider (
vercel,netlify,fly, and so on). - Environment label (
production,staging,preview). - Env-var overrides in the
deployment_envJSON column. - Deployment history with per-version rollback.
- Live credential binding so the canvas node can render “Not Connected” when no credential exists yet.
orchestrator/app/models.py defines DeploymentTarget, DeploymentTargetConnection, Deployment, and DeploymentCredential. The canvas components are app/src/components/DeploymentTargetNode.tsx and app/src/components/edges/DeploymentEdge.tsx.
Provider catalog
OpenSail ships 22 targets grouped by deploy type. Classification lives inorchestrator/app/services/deployment/manager.py and is mirrored in app/src/components/DeploymentTargetNode.tsx.
Serverless and full-stack (11)
| Provider | Slug | Auth | Notes |
|---|---|---|---|
| Vercel | vercel | OAuth | Source mode default, framework detection |
| Netlify | netlify | OAuth | Pre-built upload via Netlify Files API |
| Cloudflare Pages and Workers | cloudflare | API token | Pre-built, account_id required |
| DigitalOcean App Platform (source) | digitalocean | API token | Requires git remote on project |
| Railway | railway | API token | Requires git remote |
| Fly.io | fly | API token | Container push to Fly Machines |
| Heroku | heroku | API key | Source tarball upload |
| Render | render | API key | Requires git remote |
| Koyeb | koyeb | API token | Serverless, optional org_slug |
| Zeabur | zeabur | API key | ZIP upload, region optional |
| Northflank | northflank | API token | Requires git remote |
Static hosting (4)
| Provider | Slug | Auth | Notes |
|---|---|---|---|
| GitHub Pages | github-pages | GitHub PAT | repo scope, static only |
| Surge | surge | Email + token | Run surge token in the CLI to fetch |
| Deno Deploy | deno-deploy | Access token | org_id required |
| Firebase Hosting | firebase | Service-account JSON | site_id required |
Container push (4)
| Provider | Slug | Auth | Notes |
|---|---|---|---|
| AWS App Runner | aws-apprunner | Access key + secret | Pushes to ECR, then App Runner |
| GCP Cloud Run | gcp-cloudrun | Service-account JSON | Pushes to Artifact Registry |
| Azure Container Apps | azure-container-apps | Tenant, client, secret, subscription | Pushes to ACR |
| DigitalOcean Container Apps | do-container | API token | Pushes to DOCR |
Registry and export (3)
| Provider | Slug | Auth | Notes |
|---|---|---|---|
| Docker Hub | dockerhub | Username + PAT | Registry push only, no runtime |
| GitHub Container Registry | ghcr | Username + PAT (write:packages) | Registry push only |
| Download and Export | download | None | Zip archive delivered to the browser |
Connecting a provider
Open Settings > Deployments (app/src/pages/settings/DeploymentSettings.tsx). Each provider card reads its requirements from /api/deployment-credentials/providers served by DeploymentManager.list_available_providers().
- OAuth
- API token
/api/deployment-oauth/vercel/authorize/api/deployment-oauth/netlify/authorize
orchestrator/app/routers/deployment_oauth.py exchanges the code, encrypts the token with the Fernet key in deployment_encryption.py, and persists a DeploymentCredential row. Vercel uses PKCE; pass team_id in metadata for team accounts.Architecture Panel usage
Open the Architecture Panel
Drop a Deployment Target
DeploymentTarget row via POST /api/projects/{slug}/deployment-targets.Draw the deployment edge
/api/projects/{slug}/deployment-targets/{target_id}/connect/{container_id}, which inserts a DeploymentTargetConnection row.Cycle the environment
production, staging, preview) on the target header to cycle values. This writes back to DeploymentTarget.environment.Edit overrides
DeploymentTargetConnection.deployment_settings.Triggering a deploy
Three entry points, one pipeline:Target node Deploy button
POST /api/projects/{slug}/deployment-targets/{target_id}/deploy. Loops over every connected container in one request. This is the standard path.Deploy modal
POST /api/deployments/{project_slug}/deploy with provider, deployment_mode, env_vars, and custom_domain. Powers the top-right Deploy button.Agent tool
What happens server-side
When a deploy fires in source or file mode,routers/deployments.py::deploy_project (or routers/deployment_targets.py::deploy_target) runs this pipeline:
- RBAC check via
get_project_with_access(Permission.DEPLOYMENT_CREATE). - Resolve the credential with project-override precedence.
- Decrypt the token with
get_deployment_encryption_service(). - Insert a
Deploymentrow withstatus="building"so the UI shows progress. - Pick the primary build container and ensure it is running.
- If
deployment_mode == "source", skip the local build (the provider builds remotely). Otherwise invokeget_deployment_builder().trigger_build()which runsnpm run build(or the container-specific build) inside the live container. - Collect files with
builder.collect_deployment_files(), honoringcontainer.output_directory. - Hand files to the provider via
DeploymentManager.get_provider(name, creds). Source-mode providers callprovider.deploy(files, config). Container-push providers go throughprovider.push_image()thenprovider.deploy_image(). - Update the
Deploymentrow withstatus,deployment_url,logs,completed_at, anddeployment_metadata. - Poll or stream provider status where supported (Vercel, Netlify, cloud providers). Otherwise the initial response carries the final state.
deployment_url, status, and logs.A/B deploys
Because each target is an independent node, one container can connect to many targets. Drop a second Vercel target set topreview and a third Netlify target set to staging, then wire the same frontend container into all three. Each target keeps its own Deployment history, so URLs, rollback, and env-var overrides stay isolated.
Recommended patterns:
- Split traffic between Vercel (production) and Cloudflare Pages (preview).
- Deploy the same static build to GitHub Pages and Surge for redundancy.
- Keep
staging.myapp.comon Fly.io while production runs on AWS App Runner.
Environment matrix
Env vars flow through a four-layer merge inrouters/deployment_targets.py::_build_source_env_vars. Later layers win.
| Layer | Source | Typical use |
|---|---|---|
| 1. Auto-derived | project.git_remote_url becomes _TESSLATE_REPO_URL | Git-required providers |
| 2. Target-level | DeploymentTarget.deployment_env JSON | Values shared by every container on the target (NODE_ENV=production) |
| 3. Connection-level | DeploymentTargetConnection.deployment_settings["env_vars"] | Per-container differences against the same target |
| 4. Request-level | env_vars passed in the deploy call | One-off overrides from the modal or agent |
Per-provider caveats
Vercel
Vercel
source mode so Vercel builds on its own infrastructure. Pass team_id in metadata for team accounts. OAuth flows through /api/deployment-oauth/vercel/authorize with PKCE.Netlify
Netlify
pre-built. The local build must complete before the upload starts.Cloudflare Pages and Workers
Cloudflare Pages and Workers
pre-built only. The provider upload uses the dispatch namespace in metadata if set. account_id is mandatory.Fly.io
Fly.io
org_slug for multi-org accounts. Volumes are not auto-created, so declare them in the container’s fly.toml.AWS App Runner
AWS App Runner
GitHub Pages
GitHub Pages
repo scope. The provider publishes to the gh-pages branch.Docker Hub and GHCR
Docker Hub and GHCR
Download and Export
Download and Export
DigitalOcean
DigitalOcean
digitalocean is the source-mode alias (git deploy). do-container is the image-push alias (DOCR + App Platform container spec).Rolling back
From the target node’s deployment history, click Rollback on any prior successful row. The UI calls:Deployment row with version="{prev}-rollback", linked via deployment_metadata.rollback_from. Full provider-API rollback (Vercel alias swap, Fly release pin) is tracked in the same handler and rolls forward as each provider implements it.
Credential security
Fernet at rest
access_token_encrypted column is Fernet-encrypted with the backend key. Decryption happens only inside the deployment pipeline, never in the API response.Team-scoped defaults
user_id. Add project_id for an override that only applies to that project (useful for team members with different Vercel accounts).Token never returned
GET /api/deployment-credentials returns metadata and the is_default flag. The token field is never serialized back to the client.In-place rotation
Common errors
No credentials found for {provider}
No credentials found for {provider}
DeploymentCredential exists for this user and project. Connect the provider in Settings > Deployments, or pass project_id when creating the credential for a project-scoped override.Please connect your {provider} account first
Please connect your {provider} account first
Container {name} is not running
Container {name} is not running
Build failed: {stderr}
Build failed: {stderr}
container.build_command, install missing dependencies, and read the logs attached to the Deployment row. For long builds, split the project into smaller containers or switch to source mode.This provider deploys from a git repository...
This provider deploys from a git repository...
railway, render, digitalocean, github-pages, northflank) need a git remote on the project. Link a repo via the Git panel and retry.OAuth scope or 401 from Vercel / Netlify
OAuth scope or 401 from Vercel / Netlify
External provider deployments are not available in desktop mode
External provider deployments are not available in desktop mode
local and docker runtimes.Provider 403 quota exceeded
Provider 403 quota exceeded
Build timeout
Build timeout