# Run a GitHub repo

URL: https://briq.cloud/docs/guides/run-a-github-repo

> An app from a repo, running with a URL. The briq downloads the code itself, and nothing is built on your side.

Recipes:

- [Python app](https://briq.cloud/cookbook/python.md): Your Python code running as a service, from files or a GitHub repo: it installs requirements.txt and starts it. No image to build.
- [Node.js app](https://briq.cloud/cookbook/node.md): Your Node.js code running as a service, from files or a GitHub repo: it installs package.json and starts it. No image to build.
- [Bun app](https://briq.cloud/cookbook/bun.md): Your TypeScript or JavaScript running on Bun, from files or a GitHub repo: it installs package.json and starts it. No build step.
- [Go app](https://briq.cloud/cookbook/go.md): Your Go code running as a service, from files or a GitHub repo: it builds the module and starts the binary. No image to build.
- [Ruby app](https://briq.cloud/cookbook/ruby.md): Your Ruby code running as a service, from files or a GitHub repo: it bundles the Gemfile and starts it. No image to build.
- [Rust app](https://briq.cloud/cookbook/rust.md): Your Rust crate running as a service, from files or a GitHub repo: it builds a release and runs it. No image to build.
- [PHP app](https://briq.cloud/cookbook/php.md): Your PHP code served by PHP's built-in server, from files or a GitHub repo. No image to build.
- [Static site](https://briq.cloud/cookbook/static.md): HTML, CSS, JavaScript and images served by nginx, from files or a folder of a GitHub repo. No build, no image.
- [Nginx gateway](https://briq.cloud/cookbook/nginx.md): A gateway (reverse proxy): one URL for several briqs of a stack, routed by path (/api/ to the back end, / to the front end). One origin for the browser, nothing to change in the apps.

Ask your agent to "run github.com/acme/shop". It passes the repo's address, and the briq downloads
the code itself.

## One call

```text
briq_run({
  recipe: "node",
  params: {
    repo: { url: "github.com/acme/shop" },
    build: "npm run build",
    start: "npm start",
    port: 3000
  },
  expose: "private"
})
→ bq_7f1… app (node:22-slim) running · url: https://app-x2kd.briq.run/?briq_token=… · …
```

## What happens

1. The briq downloads the branch's latest commit, unless its volume already has it.
2. It installs dependencies when a lockfile changed.
3. It runs `build` when the commit changed.
4. It runs `start` with `PORT` set, and waits until the port answers.

A first build can take minutes. `briq_status` shows `creating` meanwhile, and `briq_logs` shows each
step.

## What `repo` takes

| Field   | What it is                                                                                                                  |
| ------- | --------------------------------------------------------------------------------------------------------------------------- |
| `url`   | `github.com/acme/shop`, `https://github.com/acme/shop.git` or `acme/shop`. On another host: an [archive URL](#another-host) |
| `ref`   | A branch, a tag or a commit sha. Default: the default branch. A full sha pins the code                                      |
| `dir`   | The app's folder in the repo, like `backend`. Install, build and start run there                                            |
| `token` | For a [private repo](#a-private-repo)                                                                                       |

The recipe also takes `install`, `build`, `start`, `port` (8080), `env`, `size` and `diskGb` (2 GB).

## Each language

| Recipe                     | Installs                                                | Starts with           |
| -------------------------- | ------------------------------------------------------- | --------------------- |
| [node](https://briq.cloud/cookbook/node)     | `npm ci`, `pnpm install` or `yarn install`, by lockfile | `npm start`           |
| [bun](https://briq.cloud/cookbook/bun)       | `bun install`                                           | `bun run start`       |
| [python](https://briq.cloud/cookbook/python) | `requirements.txt`, or `pyproject.toml` (editable)      | `python app.py`       |
| [ruby](https://briq.cloud/cookbook/ruby)     | `bundle install`                                        | `ruby app.rb`         |
| [php](https://briq.cloud/cookbook/php)       | nothing                                                 | PHP's built-in server |
| [go](https://briq.cloud/cookbook/go)         | builds at each start, from its cache                    | the binary            |
| [rust](https://briq.cloud/cookbook/rust)     | builds at each start, from its cache                    | `cargo run --release` |
| [static](https://briq.cloud/cookbook/static) | nothing: serves `dir` as it is                          | nginx                 |

Take `start` and `port` from the README. A Next.js app: `build: "npm run build"`, `start: "npm start"`,
`port: 3000`.

## Another host

On GitLab, Bitbucket or Codeberg, pass the `https` URL of a `.tar.gz` archive of the code:

```text
repo: { url: "https://gitlab.com/acme/shop/-/archive/main/shop-main.tar.gz" }
```

* The briq downloads it at each start, and unpacks it only when it changed.
* `ref` does not apply: the version is in the URL.
* A private archive takes `token`, sent as `Authorization: Bearer`.

## A new commit

* A briq starting from scratch looks the branch up again.
* `nano` and `small` wake from a memory snapshot: the app keeps its commit.
* `medium` and `large` start from scratch on each wake. A new commit is built before the app answers.
* To run a new commit now: `briq_fork` the briq, then `briq_destroy` the old one.
* To pin a version: pass a full commit sha as `ref`.

## Several services

One briq per service, each with its own `dir`, and an [Nginx gateway](https://briq.cloud/cookbook/nginx) in front.
The browser sees one URL: no CORS, no back end address built into the front end. Run each call once
the one before is running.

Here is [fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template):

```text
briq_run({ recipe: "postgres", stack: "shop" })
→ outputs: DATABASE_URL=postgres://postgres:…@….internal:5432/app

briq_run({
  recipe: "python", name: "backend", stack: "shop",
  params: {
    version: "3.14",
    repo: { url: "github.com/fastapi/full-stack-fastapi-template", dir: "backend" },
    build: "mkdir -p app/frontend && bash scripts/prestart.sh",
    start: "fastapi run app/main.py --host :: --port $PORT",
    env: {
      DATABASE_URL: { secret: "DATABASE_URL", value: "postgres://postgres:…@….internal:5432/app" },
      SECRET_KEY: { secret: "SECRET_KEY" },
      FIRST_SUPERUSER: "admin@example.com",
      FIRST_SUPERUSER_PASSWORD: { secret: "FIRST_SUPERUSER_PASSWORD", value: "…" }
    }
  }
})

briq_run({
  recipe: "bun", name: "frontend", stack: "shop",
  params: {
    repo: { url: "github.com/fastapi/full-stack-fastapi-template", dir: "frontend" },
    build: "VITE_API_URL= bun run build",
    start: "bunx sirv-cli ../backend/app/frontend --single --host :: --port $PORT"
  }
})

briq_run({
  recipe: "nginx", stack: "shop",
  params: { routes: { "/api/": "backend:8080", "/docs": "backend:8080", "/": "frontend:8080" } },
  expose: "private"
})
→ url: https://gateway-k3m9.briq.run/?briq_token=…
```

* **Name each code briq** (`name`): briq names are unique in a stack.
* **Empty the front end's API address** at build time (`VITE_API_URL=`): it then calls `/api/…`.
* **Serve the folder the build writes to**: here `../backend/app/frontend`, set in `vite.config.ts`.
* **Listen on `::`**: the gateway reaches the briqs over the private network, which is IPv6.
* **Migrations go in `build`**: they run once per new commit.

## A private repo

Ask the person for a fine-grained token, at github.com/settings/personal-access-tokens/new:

1. **Repository access**: *Only select repositories*, this repo only.
2. **Permissions**: *Contents*, read-only. Nothing else.
3. Set an expiration. An organization may have to approve the token.

```text
repo: {
  url: "github.com/acme/internal-api",
  token: { secret: "GITHUB_TOKEN", value: "github_pat_…" }
}
```

* The token is stored encrypted, and shown as `{ secret: "GITHUB_TOKEN" }`.
* Only the download gets it: not the install, the build or the app. `briq_exec` can still read it,
  like any secret.
* Never pass the person's own token (`gh auth token`): it reaches every repo they can reach.
* Delete the token once the briq is gone.

## When it does not start

`briq_logs` says which step failed:

| The logs say                     | Fix                                                                               |
| -------------------------------- | --------------------------------------------------------------------------------- |
| `could not read … from GitHub`   | Check the URL. A private repo needs `token`                                       |
| `… has no branch or tag named …` | Check `ref`                                                                       |
| `the repo has no folder …`       | Check `dir`                                                                       |
| An install or build error        | Fix the repo and push, or run a new briq with other `install`, `build` or `start` |

## Good to know

* **Builds need CPU.** On `small`, a Next.js, Rust or Go build can take over ten minutes. Use
  `medium`, or `large` (Hobby: with a card on file, see [pay as you go](https://briq.cloud/docs/cost#pay-as-you-go)).
* **A monorepo builds from its root**: `build: "cd /work/src && pnpm -w build"`. `pnpm` and `yarn`
  work in `build` and `start`, through corepack: pin a version with `packageManager` in
  `package.json`, or pass your own `install`.
* **The volume counts toward your plan's disk** until the briq is destroyed, stopped or failed
  ones included. Big dependencies need `diskGb: 5` or more.
* **A fork starts warm**: it copies the volume, code and dependencies included.
* **An app on `0.0.0.0`** works through its URL. Siblings need it on `::`.
