Deployment
Push code, get a container, get a URL. Mosaic detects your stack from the files in the repo, builds, ships, and exposes it at {slug}.mosaic.site with automatic SSL.
Choose your stack
Mosaic auto-detects the runtime from key files in the repo:
| Build this | Runtime | Key file |
|---|---|---|
| Static site / SPA | HTML + CSS + JS | index.html |
| API / backend | Node.js 20 | package.json |
| API / data app | Python 3.12 | requirements.txt |
| System service | Go | go.mod |
| System service | Rust | Cargo.toml |
| Backend | PHP | index.php |
| Backend | Ruby | Gemfile |
| Backend | Java | pom.xml |
One stack per repoIf you have both
package.json AND requirements.txt, deploy behaviour is undefined. Pick one runtime per project.Push files via API
# Single file (with auto-deploy) curl -X POST $API/{slug}/git/files \ -H "X-API-Key: $KEY" \ -d '{ "path": "src/app.js", "content": "console.log(\"hello\")", "message": "Add app.js", "deploy": true }' # Batch — up to 500 files in one atomic commit curl -X POST $API/{slug}/git/files/batch \ -H "X-API-Key: $KEY" \ -d '{ "files": [ {"path": "index.html", "content": "<h1>Hello</h1>"}, {"path": "style.css", "content": "body { margin: 0; }"} ], "message": "Initial commit", "deploy": true }'
Push via git (alternative)
git clone https://git.mosaic.site/{user}/{slug}.git cd {slug} git add . && git commit -m "My app" && git push
With auto_deploy enabled in project settings, each push triggers a deploy.
Deploy with env vars
curl -X POST $API/{slug}/deploy \ -H "X-API-Key: $KEY" \ -d '{ "repo_url": "https://git.mosaic.site/.../{slug}.git", "branch": "main", "env_vars": { "MOSAIC_API_KEY": "mk_your_key", "NODE_ENV": "production" } }'
Env vars are injected into the container at runtime. Your app reads them via process.env (Node) or os.environ (Python).
Poll status & logs
curl $API/{slug}/deploy/status -H "X-API-Key: $KEY" curl $API/{slug}/deploy/logs -H "X-API-Key: $KEY"
Status moves through pending → detecting → configuring → running, typically 15–30 seconds.
Rollback
# Roll back to specific version curl -X POST $API/{slug}/deploy/rollback \ -H "X-API-Key: $KEY" -d '{"version": 3}' # Roll back to most recent successful deploy curl -X POST $API/{slug}/deploy/rollback \ -H "X-API-Key: $KEY" -d '{}'
Custom domains
# Add a domain curl -X POST $API/{slug}/domains \ -H "X-API-Key: $KEY" \ -d '{"domain":"myapp.example.com"}' # Verify DNS curl -X POST $API/{slug}/domains/verify -H "X-API-Key: $KEY"
DNS setup — pick one:
- CNAME —
yourdomain.com → {slug}.mosaic.site - A record —
yourdomain.com → 199.127.108.254
SSL is automatic via Let's Encrypt. Custom domains survive redeploys.
Runtime gotchas
- Node.js — bind to
process.env.PORT || 8080 - Python — bind to
0.0.0.0:8080(e.g.uvicorn app:app --host 0.0.0.0 --port 8080) - Static — just have an
index.html, no server config needed - Containers are ephemeral — don't store uploads on disk, use Storage
- Don't ship SQLite — use Postgres 17
Endpoints
| Endpoint | Method | Description |
|---|---|---|
| /{slug}/git/files | POST | Push single file |
| /{slug}/git/files/batch | POST | Push up to 500 files |
| /{slug}/deploy | POST | {repo_url, branch?, env_vars?} |
| /{slug}/deploy/status | GET | Deployment status |
| /{slug}/deploy/history | GET | Deployment history |
| /{slug}/deploy/rollback | POST | {version?} |
| /{slug}/deploy/logs | GET | Build + runtime logs |
| /{slug}/restart | POST | Restart container |
| /{slug}/stop | POST | Stop container |
| /{slug}/start | POST | Start stopped container |
| /{slug}/settings | GET PATCH | auto_deploy, is_public |
| /{slug}/domains | GET POST DEL | Custom domain CRUD |
| /{slug}/domains/verify | POST | Verify DNS |