Guides
Step-by-step walkthroughs for deploying every type of app, connecting integrations, and managing your deployments.
Quick Start
Go from zero to a live app in three steps.
Install the CLI
$ curl -fsSL https://leash.build/install.sh | sh
Sign in
$ leash login
? How would you like to sign in?
> Continue with Google
Email & Password
Deploy
$ cd my-app && leash deploy
...
✓ Deployed successfully!
→ https://my-app-arvin.un.leash.build
That's it. Your app is live with HTTPS, a custom subdomain, and zero configuration.
Deploy HTML
Deploy a single HTML file or a directory containing an index.html. Perfect for Claude Code artifacts, prototypes, and quick demos.
Single file
Use the --html flag to deploy any standalone HTML file.
$ leash deploy --html artifact.html
✓ Deployed static site
→ https://artifact-arvin.un.leash.build
Directory with index.html
If your directory contains an index.html, Leash auto-detects it as a static site.
$ cd my-static-site
$ leash deploy
✓ Detected static site
✓ Deployed successfully!
→ https://my-static-site-arvin.un.leash.build
Tip: Claude Code artifacts
When Claude generates an HTML artifact, save it to a file and deploy it in one command. Great for sharing interactive visualizations, dashboards, and prototypes with teammates.
Deploy Next.js
Leash detects Next.js automatically from your package.json. Before deploying, it runs a preflight build locally to catch errors early.
$ cd my-nextjs-app
$ leash deploy
✓ Detected Next.js 15
✓ Preflight build passed
✓ Image built and pushed
✓ Deployed successfully!
→ https://my-nextjs-app-arvin.un.leash.build
Common issue: TypeScript target
If your build fails with syntax errors, your tsconfig.json may be targeting ES5. Update it to a modern version:
{"compilerOptions": {"target": "ES2017","module": "esnext"}}
What the preflight checks
- Runs
npm run buildlocally - Catches type errors before remote build
- Validates that the build output is correct
Deploy Flask
Leash detects Python apps by the presence of requirements.txt. Flask apps are auto-detected and served with gunicorn.
Example app
from flask import Flask, jsonifyapp = Flask(__name__)@app.route("/")def index():return "<h1>Hello from Leash!</h1>"@app.route("/api/health")def health():return jsonify({"status": "ok"})if __name__ == "__main__":app.run(host="0.0.0.0", port=8080)
Dependencies
flaskgunicorn
Deploy
$ leash deploy
✓ Detected Flask (Python)
✓ Image built and pushed
✓ Deployed successfully!
→ https://my-flask-app-arvin.un.leash.build
Tip
Include gunicorn in your requirements.txt. Leash uses it as the production server automatically.
Deploy Express
Any Node.js app with a package.json containing a start script deploys out of the box.
Example app
const express = require('express')const app = express()const port = process.env.PORT || 8080app.use(express.json())app.get('/', (req, res) => {res.json({ message: 'Hello from Leash!' })})app.get('/api/health', (req, res) => {res.json({ status: 'ok', uptime: process.uptime() })})app.listen(port, () => {console.log(`Server running on port ${port}`)})
package.json
{"name": "my-express-app","version": "1.0.0","scripts": {"start": "node index.js"},"dependencies": {"express": "^4.18.0"}}
Deploy
$ cd my-express-app
$ leash deploy
✓ Detected Node.js
✓ Image built and pushed
✓ Deployed successfully!
→ https://my-express-app-arvin.un.leash.build
Important: use process.env.PORT
Leash injects the PORT environment variable at runtime. Make sure your app listens on process.env.PORT instead of hardcoding a port number.
Deploy Go
Leash detects Go apps by the presence of go.mod. Just deploy from your project directory.
Example app
package mainimport ("encoding/json""fmt""net/http""os")func main() {port := os.Getenv("PORT")if port == "" {port = "8080"}http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello from Leash!")})http.HandleFunc("/api/health", func(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json")json.NewEncoder(w).Encode(map[string]string{"status": "ok"})})fmt.Printf("Server running on port %s\n", port)http.ListenAndServe(":"+port, nil)}
go.mod
module my-go-servicego 1.22
Deploy
$ cd my-go-service
$ leash deploy
✓ Detected Go
✓ Image built and pushed
✓ Deployed successfully!
→ https://my-go-service-arvin.un.leash.build
Deploy Docker
If a Dockerfile exists in your project root, Leash uses it directly instead of auto-detecting a framework. This gives you full control over the build process.
$ leash deploy
✓ Detected Dockerfile
✓ Building from Dockerfile...
✓ Image built and pushed
✓ Deployed successfully!
→ https://my-app-arvin.un.leash.build
When to use a Dockerfile
- You need system-level dependencies not covered by Nixpacks
- You want multi-stage builds for smaller images
- Your app uses a language or framework Leash doesn't auto-detect
- You need precise control over the runtime environment
Important: expose the right port
Your container must listen on the port specified by the PORT environment variable (defaults to 8080). Use EXPOSE 8080 in your Dockerfile and read $PORT at runtime.
Integrations
Leash integrations let your deployed apps access third-party services on behalf of each user. Connect once on the dashboard, and every app you deploy can use them.
How it works
Connect once, use everywhere
Connect your accounts on leash.build. Every app you deploy can access them without per-app configuration.
Per-user auth model
When someone uses your app, they authorize with their own account. Your app never sees other users' data.
Two access modes
Access integrations via the TypeScript SDK (REST) or through the MCP protocol for AI agents.
Available providers
Gmail
Send, read, and search email
Calendar
List events, create meetings
Drive
List, read, and search files
Connect flow
Go to your Dashboard on leash.build and navigate to Integrations
Click Connect next to the provider you want and authorize access via OAuth
Done. All your deployed apps can now use this integration.
Or connect from the CLI:
$ leash integrations:connect gmail
✓ Gmail connected for @arvin
$ leash integrations:status
gmail connected
calendar not connected
drive not connected
Databases
Leash provides managed PostgreSQL databases. When you deploy an app that uses a database, the CLI detects it and offers to create one for you.
Automatic Detection
The CLI detects database dependencies in your package.json, requirements.txt, go.mod, etc. If it finds PostgreSQL packages (pg, prisma, psycopg, pgx, etc.), it offers to provision a database.
$ leash deploy
✓ Detected: flask (python)
⚠ Your app uses PostgreSQL (psycopg)
Options:
[1] Create a Leash database (free with your plan)
[2] Paste your own database URL
[3] Skip — I'll configure it later
Choice (1/2/3): 1
✓ Database created — DATABASE_URL injected
How It Works
- Each app gets its own isolated PostgreSQL database and user
DATABASE_URLis automatically injected as an environment variable- Your ORM (Prisma, SQLAlchemy, etc.) creates tables on first connection
- Daily automated backups with 7-day retention
Limits
Common Issues
- "too many connections" — Use connection pooling (PgBouncer or app-level). Close connections after each request. Max 10 concurrent per app.
- "canceling statement due to statement timeout" — Query exceeded 30 seconds. Optimize your query, add indexes, or paginate results.
- "connection refused" — DATABASE_URL only works from apps deployed on Leash. It uses an internal socket connection.
Bring Your Own Database
If you prefer to use your own database (Supabase, Neon, MongoDB Atlas, etc.), choose option [2] during deploy or set the URL manually:
$ leash env set DATABASE_URL postgresql://user:pass@host:5432/dbname
For MongoDB, use MONGODB_URI. For Redis, use REDIS_URL.
Environment Variables
Set secrets and configuration for your deployed apps. Variables are encrypted at rest and injected at runtime. You must redeploy for changes to take effect.
Set a variable via CLI
$ leash env set DATABASE_URL "postgresql://user:pass@host/db"
✓ DATABASE_URL set
? Redeploy now to apply changes? (Y/n)
The CLI prompts you to redeploy immediately so the new value takes effect.
List variables
$ leash env list
DATABASE_URL = postgresql://...
API_KEY = sk-****
NODE_ENV = production
Delete a variable
$ leash env delete API_KEY
✓ API_KEY deleted
Dashboard management
You can also manage environment variables from the dashboard. Navigate to your app, click Settings, and scroll to the Environment Variables section. The dashboard provides a Save & Redeploy button that applies changes and triggers a fresh deploy in one step.
Remember: redeploy to apply
Environment variables are injected at container start time. Changing a variable does not affect a running deployment -- you must redeploy for the new value to take effect.
Access Control
Control who can access your deployed apps. Set visibility during deploy or change it later from the dashboard.
Public
Anyone with the URL can access the app. This is the default for all deployments.
Private
Only the app owner can access it. Requires login to view.
Team
Only members of your organization can access. Requires Google sign-in with a matching company email domain.
Set visibility during deploy
$ leash deploy --visibility private
# Options: public, private, team
Change visibility later
Open your app in the Dashboard, go to Settings, and update the visibility level. Changes take effect immediately -- no redeploy required.