Skip to content

Build Pipeline

When you push code to your repository, TMA.sh automatically detects your framework, builds your app, and deploys the output. This page explains each step of that process.

TMA.sh inspects your package.json to determine how to build your project. Three frameworks are supported:

FrameworkDetectionBuild commandOutput directory
Vitevite in dependencies or devDependenciesbun run builddist/
Astroastro in dependencies or devDependenciesbun run builddist/
Plain HTMLNo framework detectedStatic copy./

Detection follows priority order: Vite is checked first, then Astro, then the fallback to plain HTML. If your project uses a different setup, you can override the install command, build command, and output directory in project settings.

The full pipeline from webhook to live deployment:

1. GitHub webhook received
2. Deployment record created (status: queued)
3. Build job enqueued to Cloudflare Queue
4. Build container starts
a. Clone repository at commit SHA
b. Install dependencies (bun install)
c. Run build command (bun run build)
d. Validate output (index.html must exist)
e. Upload assets to R2
f. Update KV routing tables
g. Update Telegram bot menu URL
5. Deployment status: ready

Each step is recorded in the deployment’s build log. If any step fails, the deployment is marked as failed and the previous production deployment continues serving traffic.

A deployment moves through a fixed set of statuses:

queued → building → deploying → ready
failed
Any status (ready, failed, etc.) → cleaned → purged
  • queued — Deployment record exists, waiting for a build container.
  • building — Build container is running: installing dependencies, executing the build command.
  • deploying — Build succeeded. Assets are being uploaded and routing is being updated.
  • ready — Deployment is live and serving traffic.
  • failed — Something went wrong. Build logs contain the error details.
  • cleaned — An old deployment beyond the retention window, marked for cleanup by the cron job. Applies to any deployment (including ready ones), not just failed builds.
  • purged — R2 assets have been permanently deleted by the next cleanup cron run after being marked as cleaned.

Default build settings are determined by framework detection, but you can override them in project settings:

{
"installCommand": "bun install",
"buildCommand": "bun run build",
"outputDirectory": "dist/"
}

Common overrides include custom build commands (e.g., bun run build:telegram), different output directories, or additional install steps.

TMA.sh is primarily a static hosting platform, but it supports lightweight server-side API routes for cases where your Mini App needs backend logic.

If your project contains a server/api/index.ts or server/api/index.js file, TMA.sh detects it during the build step, bundles it with esbuild, and deploys it to Cloudflare Workers for Platforms. Your API routes are then accessible at:

https://{project}.tma.sh/api/*

Server routes have access to KV storage and environment variables defined in your project’s secrets. They do not have access to a per-project database in the current version.

server/api/index.ts
import { Hono } from "hono"
const app = new Hono()
app.get("/api/health", (c) => {
return c.json({ status: "ok" })
})
export default app

If your project contains a bot/index.ts or bot/index.js file, TMA.sh bundles it separately and deploys it as a bot webhook handler. This allows your Telegram bot to respond to commands and messages alongside serving the Mini App.

Build logs are streamed to R2 as the build progresses and are accessible from the dashboard. Each deployment retains its build log for debugging. Logs include:

  • Framework detection results
  • Dependency installation output
  • Build command output (stdout and stderr)
  • Asset upload summary (file count, total size)
  • Routing update confirmation
  • Timing information for each step

Builds run in isolated Cloudflare Containers with:

  • Runtime: Bun (latest stable)
  • Memory: Sufficient for typical frontend builds
  • Timeout: Builds that exceed the time limit are terminated and marked as failed
  • Network: Outbound access for installing dependencies from npm registries
  • Isolation: Each build runs in its own container with no access to other projects