Docs/ CLI/ Push Deploy

Push Deploy

Deploy from a local directory with sh0 push. No Git repository required.

What is Push Deploy

sh0 push takes a local directory, detects the stack (Node.js, Python, Go, Rust, etc.), packages the files, uploads them to your server, builds a container, and returns a live URL. The entire flow happens in one command.

This is the fastest way to go from code to a running deployment. No Git setup, no repository configuration, no webhook integration -- just push and go.

Basic Usage

Deploy current directory
sh0 push

Output:

Output
Pushing my-app
  Detected nodejs (Next.js) -- 85/100 health
  Uploading 42 files (2.3 MB) ··· OK 0.8s
  Building ··· OK 32.4s
  Deploying ··· OK 2.1s
  Live in 35.3s
  -> https://my-app.sh0.app

You can also push a specific directory or customize the app name:

Custom options
sh0 push ~/projects/api --name my-api --port 3000

How It Works

The push flow has six steps:

  1. Resolve directory -- Defaults to the current directory. Verifies the path exists.
  2. Check link -- If .sh0/link.json exists, this is a re-push to an existing app.
  3. Detect stack -- Identifies the framework and language (20+ stacks supported).
  4. Run health check -- Scores the project on best practices. Warns on blocking issues.
  5. Package and upload -- Creates an in-memory ZIP, respecting ignore patterns. Uploads via multipart form.
  6. Build and deploy -- The server builds a container, starts it, and assigns a domain. Build logs stream in real time.

Options

FlagDefaultDescription
[path].Directory to push
--name <name>Directory nameApp name (lowercase, alphanumeric, hyphens)
--project <id>Default projectProject to deploy into
--port <port>Auto-detectedApplication port inside the container
--no-checkfalseSkip the health check
--timeout <secs>600Maximum seconds to wait for deployment

.sh0ignore

Control which files are excluded from the upload. Uses the same syntax as .gitignore. If no .sh0ignore exists, the CLI falls back to .dockerignore, then .gitignore.

.sh0ignore
# Build artifacts
node_modules/
dist/
.next/

# Environment
.env
.env.*

# IDE
.vscode/
.idea/

The following directories are always excluded, regardless of ignore files:

  • .git/, node_modules/, __pycache__/, .env*
  • target/, .next/, .nuxt/, .svelte-kit/, dist/
  • venv/, .venv/, .sh0/, .DS_Store

After the first push, the CLI creates .sh0/link.json in your project directory. This file links the local directory to the remote app so subsequent pushes update the same deployment.

.sh0/link.json
{
  "app_id": "a1b2c3d4",
  "app_name": "my-app",
  "server_url": "https://panel.example.com"
}
Tip
Add .sh0/ to your .gitignore. The link file contains server-specific information and should not be shared across environments.

Health Checks

Before uploading, sh0 push runs the same Code Health Check available via sh0 check. It scores your project from 0 to 100 and warns about issues that could cause build failures.

Skip the health check with --no-check if you know what you're doing.

Re-push Behavior

When .sh0/link.json exists, running sh0 push uploads to the existing app instead of creating a new one. The server creates a new deployment, builds the updated code, and performs a blue-green swap if configured.

To deploy as a new app instead, use --name new-app-name or delete .sh0/link.json.

Auto-Push with sh0 watch

For development, use sh0 watch to automatically re-push on file changes:

Watch mode
sh0 watch --debounce 3000

This watches the current directory and re-pushes after 3 seconds of inactivity. Respects .sh0ignore patterns and runs an initial push on start. See the Commands Reference for all options.

CI/CD Integration

Use sh0 push in CI/CD pipelines for projects that don't use Git-based deployment. Here's a GitHub Actions example:

.github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install sh0
        run: curl -fsSL https://get.sh0.dev | bash
      - name: Deploy
        env:
          SH0_API_URL: ${{ secrets.SH0_API_URL }}
          SH0_API_TOKEN: ${{ secrets.SH0_API_TOKEN }}
        run: sh0 push --name my-app