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

# Git Deployment

> Connect a Git repository to your pod and deploy automatically on every push.

Deploy code to your pod by connecting a GitHub repository or any Git URL. Push to a branch and your code deploys automatically — with dependency installation, build commands, and deployment history.

<Tip>
  Starting fresh? You don't need to create the pod first. [`instapods deploy --repo <url>`](/cli/deploy) detects the stack, creates the pod, connects the repo, and runs the first build in one step — the same flow as the **From GitHub** option in the create-pod wizard and the "Deploy to InstaPods" button.
</Tip>

## Quick Start

```bash theme={null}
# Create a pod
instapods pods create my-api --preset nodejs -w

# Connect a GitHub repo and trigger the first deploy
instapods git connect my-api --repo https://github.com/you/my-api --deploy

# That's it. Push to main and it auto-deploys.
```

## Deploying a Repo From Scratch

If the pod doesn't exist yet, the **From GitHub** path in the create wizard reads your repository
first and proposes a complete deploy plan, which you can edit before anything is created:

* **Runtime and plan** - detected from your root files. Every preset starts on Launch unless the
  plan is raised for a reason you can see (a repo that needs a managed database starts on Build,
  because Launch can't run one).
* **Install, build, start and release commands** - detected, and editable inline.
* **Managed services** - when the repo clearly needs PostgreSQL, MySQL or Redis, they're installed
  on first deploy and their connection strings written into your app's environment, so the app boots
  connected. `DATABASE_URL` and `REDIS_URL` are always written; an app that reads a different name
  (`POSTGRES_PRISMA_URL`, say) gets that one filled too.
* **Environment variables** - the wizard lists the ones your repo needs and asks for the values it
  can't know. It handles two kinds itself:
  * *Generated secrets* (session and auth keys) are minted server-side, stored once, and reused on
    every redeploy - regenerating them would sign everyone out on each deploy.
  * *Self-URL variables* (`APP_URL`, `NEXTAUTH_URL`, …) are filled with the pod's own URL at deploy
    time, because the pod has no URL yet while you're filling the form. Type a value yourself to
    pin a custom domain instead.
* **Database migrations** - a detected migration command becomes the release command and runs on
  every deploy, after the services are wired.

Services require the Build plan or higher.

### Laravel

A Laravel repo is recognised as a special case: the wizard offers to provision **MySQL** with it and
starts it on the Build plan (Launch has no services), writes the database credentials into `.env`,
runs `php artisan migrate --force` as the release command, and builds your front-end assets.

### From the CLI

```bash theme={null}
# Detect the stack, create the pod, connect the repo, run the first build
instapods deploy --repo https://github.com/you/my-api

# A monorepo: deploy one app out of the repo
instapods deploy --repo https://github.com/you/monorepo --subdir apps/web
```

The CLI path creates the pod and deploys it; environment variables and managed services are set
afterwards with [`instapods env set`](/guides/environment-variables) and
[`instapods services add`](/cli/services). Use the dashboard wizard when you want them wired in
before the first build.

## Connecting a Repository

### GitHub Repository

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # Connect and deploy immediately
    instapods git connect my-app --repo https://github.com/you/repo --deploy

    # Connect to a specific branch
    instapods git connect my-app --repo https://github.com/you/repo --branch develop

    # Connect a private repo with a personal access token
    instapods git connect my-app \
      --repo https://github.com/you/private-repo \
      --auth-token ghp_your_token_here \
      --deploy
    ```
  </Tab>

  <Tab title="Dashboard">
    1. Go to your pod's **Git** tab
    2. Enter the repository URL (e.g., `https://github.com/you/repo`)
    3. Select the branch to deploy from (default: `main`)
    4. Click **Connect**
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    curl -X POST https://app.instapods.com/api/pods/my-app/git \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "repo_url": "https://github.com/you/repo",
        "branch": "main",
        "auto_deploy": true
      }'
    ```
  </Tab>
</Tabs>

### Connecting Your GitHub Account

Your GitHub connection belongs to your account, not to a pod, so you can set it up before you have
any pods. Go to **Integrations** in the sidebar (`/dashboard/integrations`) - the GitHub card shows
whether you're connected, which accounts and organisations the InstaPods app is installed on, and
how many repositories each one exposes.

That repository count is the thing to check when the repo picker looks empty: the GitHub App is
installed per account or organisation and per repository, so a repo in an org you didn't grant
access to simply won't appear. **Configure on GitHub**, at the bottom of the card, takes you
straight to the installation settings where you can add it.

<Note>
  **A private repository needs this connection.** Public repos deploy without one, but pasting a
  private repo's URL without a connected GitHub account is refused with "this looks like a private
  repository - connect GitHub to deploy it, or use a public repo". Connect the account (and grant
  the app access to that repo) and paste the URL again.
</Note>

<Tip>
  Connecting GitHub helps with public repos too. GitHub rate-limits unauthenticated downloads per
  IP address, so a clone of a perfectly public repo can be refused because the pod's host is busy,
  not because of anything on your side. InstaPods retries that automatically and
  [names it as the cause](/support/troubleshooting#when-a-deploy-fails) when it still fails; an
  authenticated clone never runs into the limit.
</Tip>

### Any Git URL

You can connect any publicly accessible Git repository:

```bash theme={null}
instapods git connect my-app --repo https://gitlab.com/you/repo
instapods git connect my-app --repo https://bitbucket.org/you/repo
```

For private repositories, provide an auth token:

```bash theme={null}
instapods git connect my-app \
  --repo https://gitlab.com/you/private-repo \
  --auth-token glpat-your_token_here
```

## Auto-Deploy on Push

When a repository is connected with auto-deploy enabled (the default), pushing to the configured branch triggers a deployment automatically.

For GitHub repositories, InstaPods sets up a webhook that fires on every push. For other Git providers, you can configure a webhook manually using the URL shown in the dashboard.

### How a Deploy Works

1. **Pull** — The latest code is pulled from the configured branch
2. **Install** — Dependencies are installed based on the preset (see below)
3. **Build** — Build commands run if configured
4. **Restart** — The application service restarts with the new code

The entire process typically takes 5-30 seconds depending on the size of your dependencies.

### Skip a Deploy

Add `[skip deploy]` to your commit message to push without triggering a deployment:

```bash theme={null}
git commit -m "update readme [skip deploy]"
git push
```

## Build Auto-Detection

InstaPods uses AI to analyze your project files and automatically determine the right install, build, and start commands for each deploy. This works for all presets and handles frameworks like Next.js, Vite, Django, Laravel, and more — without any configuration.

The AI inspects files like `package.json`, `requirements.txt`, `composer.json`, framework configs, and your directory structure. It detects:

* **Install commands** — `npm install`, `pip install -r requirements.txt`, `composer install`, etc.
* **Build commands** — `npm run build`, framework-specific builds
* **Start commands** — `node server.js`, `serve -s build`, `gunicorn app:app`, etc.
* **App port** — The port your app listens on

If AI detection is unavailable, InstaPods falls back to these defaults:

| Preset | Install Command | Build Command |
| - | - | - |
| **Node.js** | `npm install` | `npm run build` (if build script exists) |
| **Python** | `pip install -r requirements.txt` | None |
| **PHP** | `composer install` | None |
| **Static** | None | None |

<Tip>
  The AI auto-detection handles SPAs and frameworks that need a custom start command (e.g., `serve -s build` for Vite, `node server.js` for Next.js standalone). You don't need to configure these manually.
</Tip>

### Package Manager

The package manager is not a guess. If your repo has a `bun.lock`, `pnpm-lock.yaml` or `yarn.lock`,
or a `packageManager` field in `package.json`, InstaPods uses that tool for both install and build -
`npm` cannot resolve a `workspace:` dependency from a bun, pnpm or yarn monorepo, so getting this
wrong would break the install outright. Make sure your **start** command uses the same tool
(`bun run start`, not `npm start`, for a bun project).

### Monorepos

A pod runs one app. In a monorepo, build only the package you're going to serve:

```bash theme={null}
bun run build --filter=web        # turbo / bun
pnpm --filter web build           # pnpm
npm run build -w web              # npm workspaces
```

A bare `turbo run build` or `pnpm -r build` builds every sibling app, and one unrelated package
failing fails your whole deploy. Use `--subdirectory` (below) when the app you want lives in a
subfolder of the repo.

<Note>
  A repo containing two runtimes - a Node frontend and a Python backend, say - deploys the detected
  one only, and the wizard warns you when it spots this. If the server you actually want is the
  other runtime, set a custom start command, or deploy that side to its own pod.
</Note>

### Custom Commands

Every command is editable - during the create wizard, and afterwards on the pod's **Git** tab:

| Command | When it runs |
| - | - |
| **Install** | First, to fetch dependencies |
| **Build** | After install |
| **Release** | After the build and after managed services are wired, on **every** deploy - this is your database migration |
| **Start** | The long-running process that serves your app |

The start command matters most: it's what you set when your app doesn't start the way its preset
assumes (`open-webui serve` on a Python pod, `node server.js` for a Next.js standalone build, a
`cd apps/web && bun run start` in a monorepo).

<Warning>
  A release command that fails, fails the deploy - every time, until you fix it. If a detected
  migration command is wrong for your app, edit it or clear it on the Git tab.
</Warning>

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # Set a custom build command during connect
    instapods git connect my-app \
      --repo https://github.com/you/repo \
      --build-cmd "npm ci && npm run build"

    # Deploy an app that lives in a subfolder of the repo
    instapods git connect my-app \
      --repo https://github.com/you/repo \
      --subdirectory apps/web \
      --install-cmd "pnpm install --frozen-lockfile"
    ```
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    curl -X PUT https://app.instapods.com/api/pods/my-app/git \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "install_command": "npm ci",
        "build_command": "npm run build",
        "start_command": "node server.js",
        "release_command": "npx prisma migrate deploy",
        "subdirectory": "apps/web",
        "auto_deploy": true
      }'
    ```

    Every field is optional; send only what you want to change. Send `""` to clear one and fall back
    to detection.
  </Tab>
</Tabs>

## When a Deploy Fails

Failed deployments are diagnosed automatically. The **Git** tab shows a banner on the failed
deployment naming what went wrong - a stale lockfile, missing build-time environment variables, a
monorepo sibling that broke the build, a branch that isn't on the remote, a dev script being used to
serve production - with the build log underneath. See
[Deploy Doctor](/support/troubleshooting#deploy-doctor) for the full list, and for what happens when
the app deploys fine but doesn't stay up.

## Check Git Status

See the current git configuration and last deployment status:

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    instapods git status my-app
    ```

    Output shows the connected repo, branch, auto-deploy setting, and latest deployment info.
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    curl https://app.instapods.com/api/pods/my-app/git \
      -H "Authorization: Bearer YOUR_TOKEN"
    ```

    Returns `null` if no repository is connected.
  </Tab>
</Tabs>

## Manual Deploy

Trigger a deployment manually, even if auto-deploy is off:

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # Trigger and return immediately
    instapods git deploy my-app

    # Wait for the deploy to finish
    instapods git deploy my-app -w

    # Wait with custom timeout
    instapods git deploy my-app -w --timeout 300s
    ```
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    curl -X POST https://app.instapods.com/api/pods/my-app/git/deploy \
      -H "Authorization: Bearer YOUR_TOKEN"
    ```
  </Tab>
</Tabs>

## Deployment History and Logs

Every deployment is recorded with its status, commit, and build output.

### View Deployments

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # Last 10 deployments (default)
    instapods git deployments my-app

    # Last 25 deployments
    instapods git deployments my-app -n 25
    ```
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    curl "https://app.instapods.com/api/pods/my-app/git/deployments?limit=10" \
      -H "Authorization: Bearer YOUR_TOKEN"
    ```
  </Tab>
</Tabs>

### View Build Logs

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # Logs from the latest deployment
    instapods git logs my-app

    # Logs from a specific deployment
    instapods git logs my-app deploy_abc123
    ```
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    curl https://app.instapods.com/api/pods/my-app/git/deployments/deploy_abc123 \
      -H "Authorization: Bearer YOUR_TOKEN"
    ```

    The response includes a `build_log` field with the full output.
  </Tab>
</Tabs>

## Rollback

Revert to a previous deployment:

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # Rollback to the previous deployment
    instapods git rollback my-app

    # Rollback to a specific deployment
    instapods git rollback my-app deploy_abc123

    # Skip confirmation and wait for completion
    instapods git rollback my-app -f -w
    ```
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    curl -X POST https://app.instapods.com/api/pods/my-app/git/rollback \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"deployment_id": "deploy_abc123"}'
    ```

    Omit `deployment_id` to roll back to the immediately previous deployment.
  </Tab>
</Tabs>

## GitHub Commit Status Checks

When deploying from a GitHub repository, InstaPods reports deployment status back to GitHub as commit status checks. You'll see a green checkmark (or red X) on your commits and pull requests.

This works automatically for public repositories. For private repositories, make sure the auth token you provided has `repo:status` scope.

## Disconnect

Remove the git connection from a pod:

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # With confirmation prompt
    instapods git disconnect my-app

    # Skip confirmation
    instapods git disconnect my-app -f
    ```
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    curl -X DELETE https://app.instapods.com/api/pods/my-app/git \
      -H "Authorization: Bearer YOUR_TOKEN"
    ```
  </Tab>
</Tabs>

Disconnecting removes the webhook and git configuration. Your deployed code stays in the pod — nothing is deleted.

## Full Example

Deploy a Node.js API from GitHub with auto-deploy:

```bash theme={null}
# 1. Create the pod
instapods pods create my-api --preset nodejs --plan build -w

# 2. Set environment variables
instapods exec my-api -- "cat > /home/instapod/app/.env << 'EOF'
DATABASE_URL=postgres://instapod:secret@localhost:5432/instapod
NODE_ENV=production
EOF"

# 3. Install a database
instapods services add my-api -s postgresql -w

# 4. Connect the repo (triggers first deploy)
instapods git connect my-api --repo https://github.com/you/my-api --deploy

# 5. Check deployment status
instapods git status my-api

# From now on, every push to main auto-deploys.
# View deployment history anytime:
instapods git deployments my-api
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.