Skip to content
69 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

g1t has actions of its own: g1t/deploy builds the checkout a job is in and puts it on g1t.page, opening the build with the job's token, masking the build's token and the project's secrets, and running g1t-runner deploy, with the app's url, the deployment's id and its kind as outputs; g1t/detect says what such a build would find (kind, install, build and output-dir) without building anything. Both use the g1t-runner on the machine, or download the newest release from g1t.sh/downloads/runner and check it against its SHA256SUMS. They live under actions/, and the Actions release workflow pushes each folder to its own repository in the g1t workspace and moves its v1 tag whenever main changes them, with the G1T_ACTIONS_PUBLISH_TOKEN secret its header describes.1# g1t/detect
2
3Says what a [g1t.page](https://docs.g1t.sh/guides/deployments/) build of
4the checkout would find, without building or deploying anything: the
5same rules [g1t/deploy](https://g1t.sh/g1t/deploy) builds with.
6
7```yaml
8steps:
9 - uses: actions/checkout@v5
10 - id: detect
11 uses: g1t/detect@v1
12 - if: steps.detect.outputs.kind == 'none'
13 run: echo "::error::Nothing here would be served."
g1t.page builds know the framework a project is built with, from its package's dependencies and config files: Vite (and React, Vue, Svelte, Solid or Preact on it), Astro, Next.js with `output: 'export'`, SvelteKit with the static adapter, Nuxt by `nuxi generate`, React Router and Remix in SPA mode, Gatsby, Docusaurus, Eleventy, Angular, Create React App, Hugo, Jekyll and mdBook are each built with their own command and served from the folder they write, read from their config where it moves it. A Cloudflare adapter's Worker deploys as a Workers project with no Wrangler config of the project's own: Astro's, which now writes its config for wrangler in `.wrangler/deploy/config.json` (as `@cloudflare/vite-plugin` does, and that is read too), SvelteKit's `.svelte-kit/cloudflare/_worker.js`, and OpenNext's with a `wrangler.jsonc`; a site's `_worker.js`, `_routes.json` and what `.assetsignore` lists are never uploaded, and a written config's empty binding lists are no longer warned about. A framework set up to need a server (Next.js without a static export, Astro's server output, SvelteKit's auto or node adapter, a server-rendered React Router or Remix app) fails before anything is installed, saying what to change, in place of "found nothing to serve". The project's Build command and Output directory still win. The build's log names the framework, the finish report carries it as `framework` (which the deployments service ignores for now), and `g1t-runner detect` and the `g1t/detect` action output it. What deploys has a table of every framework, and the detect action's README lists them.14 - if: steps.detect.outputs.framework == 'hugo'
15 run: echo "A Hugo site, served from ${{ steps.detect.outputs.output-dir }}"
g1t has actions of its own: g1t/deploy builds the checkout a job is in and puts it on g1t.page, opening the build with the job's token, masking the build's token and the project's secrets, and running g1t-runner deploy, with the app's url, the deployment's id and its kind as outputs; g1t/detect says what such a build would find (kind, install, build and output-dir) without building anything. Both use the g1t-runner on the machine, or download the newest release from g1t.sh/downloads/runner and check it against its SHA256SUMS. They live under actions/, and the Actions release workflow pushes each folder to its own repository in the g1t workspace and moves its v1 tag whenever main changes them, with the G1T_ACTIONS_PUBLISH_TOKEN secret its header describes.16 - if: steps.detect.outputs.install != ''
17 run: ${{ steps.detect.outputs.install }}
18```
19
20## Inputs
21
22| Input | Default | |
23| --- | --- | --- |
24| `root-dir` | The checkout | Where the project is in the checkout. |
25| `build-command` | None | A build command of your own, as `g1t/deploy` takes it. |
26| `output-dir` | None | An output folder of your own, as `g1t/deploy` takes it. |
g1t.page runs Docker deployments, behind a switch that is off until Cloudflare's container APIs are checked against g1t's account (`CONTAINERS` in the deployments service). Each container app is a Worker of g1t's own in the same Workers for Platforms namespace, so the dispatcher, custom domains, previews and take-downs reach it by name as any app: its `G1tApp` Durable Object holds a Container application (default scheduling policy, one instance, the project's **Container size**, `lite` unless chosen), starts it on the first request with the project's secrets and variables and `PORT` as its environment, waits up to 90 seconds for it to answer on its port, proxies to it, and stops it five minutes after the last request; it charges each minute awake ahead and the bytes it sends, and reports them with a token of its own to `POST /deployments/apps/<app>/meter`, which the API forwards. A build's new `registry` step gets a registry login g1t mints push-only for 15 minutes, with its app's own repository named; g1t runs only an image by digest in that repository, checked with the registry, and never hands a build a login that can pull. Container time is metered at Cloudflare's Containers price plus the margin through new price book meters (vCPU charged as busy while awake, and egress at the most a GB costs anywhere, so g1t never sells below cost), noted for the spend limit as it runs and charged with the month's Deployments line; a paused workspace's container apps stop and start no more. Settings, Deployments gets Build as (Auto, Static site, Workers, Docker), Dockerfile and Container size with each size's price an hour, and says what the last build found with what it was built with ("Static site · Astro", "Container · Dockerfile"), now that the finish report's `framework` is stored. Deploy sandboxes get Docker, `BUILD_AS` and `DOCKERFILE`, and reach `registry.cloudflare.com`; `start_deployment_build` answers `build_as` and `dockerfile` for `g1t/deploy`, which takes them as inputs, as `g1t/detect` does. The Deployments guide has Docker deployments, their prices and how they work with the evidence for it, the limitations page says what is left, and Deploy g1t to Cloudflare lists each live check to make before switching it on.27| `build-as` | `auto` | What it is built as: `auto`, `static`, `workers` or `docker`, as `g1t/deploy` takes it. |
28| `dockerfile` | None | A Dockerfile's path of your own, as `g1t/deploy` takes it. |
g1t has actions of its own: g1t/deploy builds the checkout a job is in and puts it on g1t.page, opening the build with the job's token, masking the build's token and the project's secrets, and running g1t-runner deploy, with the app's url, the deployment's id and its kind as outputs; g1t/detect says what such a build would find (kind, install, build and output-dir) without building anything. Both use the g1t-runner on the machine, or download the newest release from g1t.sh/downloads/runner and check it against its SHA256SUMS. They live under actions/, and the Actions release workflow pushes each folder to its own repository in the g1t workspace and moves its v1 tag whenever main changes them, with the G1T_ACTIONS_PUBLISH_TOKEN secret its header describes.29
30## Outputs
31
32| Output | |
33| --- | --- |
g1t.page runs Docker deployments, behind a switch that is off until Cloudflare's container APIs are checked against g1t's account (`CONTAINERS` in the deployments service). Each container app is a Worker of g1t's own in the same Workers for Platforms namespace, so the dispatcher, custom domains, previews and take-downs reach it by name as any app: its `G1tApp` Durable Object holds a Container application (default scheduling policy, one instance, the project's **Container size**, `lite` unless chosen), starts it on the first request with the project's secrets and variables and `PORT` as its environment, waits up to 90 seconds for it to answer on its port, proxies to it, and stops it five minutes after the last request; it charges each minute awake ahead and the bytes it sends, and reports them with a token of its own to `POST /deployments/apps/<app>/meter`, which the API forwards. A build's new `registry` step gets a registry login g1t mints push-only for 15 minutes, with its app's own repository named; g1t runs only an image by digest in that repository, checked with the registry, and never hands a build a login that can pull. Container time is metered at Cloudflare's Containers price plus the margin through new price book meters (vCPU charged as busy while awake, and egress at the most a GB costs anywhere, so g1t never sells below cost), noted for the spend limit as it runs and charged with the month's Deployments line; a paused workspace's container apps stop and start no more. Settings, Deployments gets Build as (Auto, Static site, Workers, Docker), Dockerfile and Container size with each size's price an hour, and says what the last build found with what it was built with ("Static site · Astro", "Container · Dockerfile"), now that the finish report's `framework` is stored. Deploy sandboxes get Docker, `BUILD_AS` and `DOCKERFILE`, and reach `registry.cloudflare.com`; `start_deployment_build` answers `build_as` and `dockerfile` for `g1t/deploy`, which takes them as inputs, as `g1t/detect` does. The Deployments guide has Docker deployments, their prices and how they work with the evidence for it, the limitations page says what is left, and Deploy g1t to Cloudflare lists each live check to make before switching it on.34| `kind` | `workers` (a `wrangler.jsonc`, `wrangler.json` or `wrangler.toml`, or a framework's Cloudflare adapter), `static` (a site a build writes), `html` (the files as they are), `container` (a `Dockerfile`, a framework set up to need a server, or a server g1t writes a Dockerfile for) or `none` (nothing to serve). |
35| `framework` | The framework it is built with, from the table below; for a container without one, `dockerfile`, or the server g1t writes a Dockerfile for (`node`, `django`, `flask`, `fastapi`, `python`, `go`, `rails`, `rack`, `laravel`, `php`). Empty when there is none. |
36| `dockerfile` | A container's own Dockerfile, relative to the project. Empty when g1t writes one, and for anything that is not a container. |
37| `port` | The port a container listens on: its Dockerfile's `EXPOSE`, else `8080`. |
g1t.page builds know the framework a project is built with, from its package's dependencies and config files: Vite (and React, Vue, Svelte, Solid or Preact on it), Astro, Next.js with `output: 'export'`, SvelteKit with the static adapter, Nuxt by `nuxi generate`, React Router and Remix in SPA mode, Gatsby, Docusaurus, Eleventy, Angular, Create React App, Hugo, Jekyll and mdBook are each built with their own command and served from the folder they write, read from their config where it moves it. A Cloudflare adapter's Worker deploys as a Workers project with no Wrangler config of the project's own: Astro's, which now writes its config for wrangler in `.wrangler/deploy/config.json` (as `@cloudflare/vite-plugin` does, and that is read too), SvelteKit's `.svelte-kit/cloudflare/_worker.js`, and OpenNext's with a `wrangler.jsonc`; a site's `_worker.js`, `_routes.json` and what `.assetsignore` lists are never uploaded, and a written config's empty binding lists are no longer warned about. A framework set up to need a server (Next.js without a static export, Astro's server output, SvelteKit's auto or node adapter, a server-rendered React Router or Remix app) fails before anything is installed, saying what to change, in place of "found nothing to serve". The project's Build command and Output directory still win. The build's log names the framework, the finish report carries it as `framework` (which the deployments service ignores for now), and `g1t-runner detect` and the `g1t/detect` action output it. What deploys has a table of every framework, and the detect action's README lists them.38| `install` | How dependencies are installed, from the lockfile: `npm ci`, `pnpm install --frozen-lockfile`, and so on, and `bundle install` for Jekyll. Empty when there is nothing to install. |
39| `build` | What builds it: your command, the package's `build` script (`npm run build`), the framework's own command, or `wrangler deploy --dry-run` for Workers. Empty when nothing does. |
40| `output-dir` | The folder served, relative to the project (`.` for the project itself): yours, a Workers project's assets directory, the folder the framework writes, or the first of `dist`, `build`, `out`, `public`, `_site`, `.output/public` that exists. Empty when a build has yet to write it, as for a Cloudflare adapter's Worker. |
41
g1t.page runs Docker deployments, behind a switch that is off until Cloudflare's container APIs are checked against g1t's account (`CONTAINERS` in the deployments service). Each container app is a Worker of g1t's own in the same Workers for Platforms namespace, so the dispatcher, custom domains, previews and take-downs reach it by name as any app: its `G1tApp` Durable Object holds a Container application (default scheduling policy, one instance, the project's **Container size**, `lite` unless chosen), starts it on the first request with the project's secrets and variables and `PORT` as its environment, waits up to 90 seconds for it to answer on its port, proxies to it, and stops it five minutes after the last request; it charges each minute awake ahead and the bytes it sends, and reports them with a token of its own to `POST /deployments/apps/<app>/meter`, which the API forwards. A build's new `registry` step gets a registry login g1t mints push-only for 15 minutes, with its app's own repository named; g1t runs only an image by digest in that repository, checked with the registry, and never hands a build a login that can pull. Container time is metered at Cloudflare's Containers price plus the margin through new price book meters (vCPU charged as busy while awake, and egress at the most a GB costs anywhere, so g1t never sells below cost), noted for the spend limit as it runs and charged with the month's Deployments line; a paused workspace's container apps stop and start no more. Settings, Deployments gets Build as (Auto, Static site, Workers, Docker), Dockerfile and Container size with each size's price an hour, and says what the last build found with what it was built with ("Static site · Astro", "Container · Dockerfile"), now that the finish report's `framework` is stored. Deploy sandboxes get Docker, `BUILD_AS` and `DOCKERFILE`, and reach `registry.cloudflare.com`; `start_deployment_build` answers `build_as` and `dockerfile` for `g1t/deploy`, which takes them as inputs, as `g1t/detect` does. The Deployments guide has Docker deployments, their prices and how they work with the evidence for it, the limitations page says what is left, and Deploy g1t to Cloudflare lists each live check to make before switching it on.42When `kind` is `none`, the step's log says what to change or add, such as
43a `Dockerfile`. [Docker deployments](https://docs.g1t.sh/guides/deployments/#docker-deployments)
44has the order in which a project's kind is decided.
g1t.page builds know the framework a project is built with, from its package's dependencies and config files: Vite (and React, Vue, Svelte, Solid or Preact on it), Astro, Next.js with `output: 'export'`, SvelteKit with the static adapter, Nuxt by `nuxi generate`, React Router and Remix in SPA mode, Gatsby, Docusaurus, Eleventy, Angular, Create React App, Hugo, Jekyll and mdBook are each built with their own command and served from the folder they write, read from their config where it moves it. A Cloudflare adapter's Worker deploys as a Workers project with no Wrangler config of the project's own: Astro's, which now writes its config for wrangler in `.wrangler/deploy/config.json` (as `@cloudflare/vite-plugin` does, and that is read too), SvelteKit's `.svelte-kit/cloudflare/_worker.js`, and OpenNext's with a `wrangler.jsonc`; a site's `_worker.js`, `_routes.json` and what `.assetsignore` lists are never uploaded, and a written config's empty binding lists are no longer warned about. A framework set up to need a server (Next.js without a static export, Astro's server output, SvelteKit's auto or node adapter, a server-rendered React Router or Remix app) fails before anything is installed, saying what to change, in place of "found nothing to serve". The project's Build command and Output directory still win. The build's log names the framework, the finish report carries it as `framework` (which the deployments service ignores for now), and `g1t-runner detect` and the `g1t/detect` action output it. What deploys has a table of every framework, and the detect action's README lists them.45
46## Frameworks
47
48| `framework` | Found by | Serves |
49| --- | --- | --- |
50| `vite`, `vite-react`, `vite-vue`, `vite-svelte`, `vite-solid`, `vite-preact` | `vite`, and the framework's Vite plugin | `dist`, or `build.outDir` |
51| `astro` | `astro` | `dist`, or `outDir`; a Worker with `@astrojs/cloudflare` |
52| `nextjs` | `next` | `out` with `output: 'export'`; a Worker with `@opennextjs/cloudflare` and a `wrangler.jsonc` |
53| `sveltekit` | `@sveltejs/kit` | `build` with `adapter-static`; a Worker with `adapter-cloudflare` |
54| `nuxt` | `nuxt` | `.output/public`, from `nuxi generate` |
55| `react-router`, `remix` | `@react-router/dev`, `@remix-run/dev` | `build/client` with `ssr: false` |
56| `gatsby` | `gatsby` | `public` |
57| `docusaurus` | `@docusaurus/core` | `build` |
58| `eleventy` | `@11ty/eleventy` | `_site` |
59| `angular` | `@angular/core` and `angular.json` | `dist/<project>/browser` |
60| `create-react-app` | `react-scripts` | `build` |
61| `hugo` | `hugo.toml`, or Hugo's `config.toml` | `public` |
62| `jekyll` | `_config.yml` and a `Gemfile` | `_site` |
63| `mdbook` | `book.toml` | `book` |
64
65[What deploys](https://docs.g1t.sh/guides/deployments/#frameworks) has
66each one's build command. Your `build-command` and `output-dir` win over
67what is detected.
g1t has actions of its own: g1t/deploy builds the checkout a job is in and puts it on g1t.page, opening the build with the job's token, masking the build's token and the project's secrets, and running g1t-runner deploy, with the app's url, the deployment's id and its kind as outputs; g1t/detect says what such a build would find (kind, install, build and output-dir) without building anything. Both use the g1t-runner on the machine, or download the newest release from g1t.sh/downloads/runner and check it against its SHA256SUMS. They live under actions/, and the Actions release workflow pushes each folder to its own repository in the g1t workspace and moves its v1 tag whenever main changes them, with the G1T_ACTIONS_PUBLISH_TOKEN secret its header describes.68
69It runs `g1t-runner detect`, found or downloaded as `g1t/deploy` finds it.