| 1 | --- |
| 2 | title: Architecture overview |
| 3 | description: How g1t is put together, from the four public Workers at the edge to the nineteen services behind them, the event bus that connects them, and the platform each one runs on. |
| 4 | --- |
| 5 | |
| 6 | import { CardGrid } from "@astrojs/starlight/components"; |
| 7 | import Aside from "../../../components/Aside.astro"; |
| 8 | import Diagram from "../../../components/Diagram.astro"; |
| 9 | import LinkCard from "../../../components/LinkCard.astro"; |
| 10 | |
| 11 | g1t is a set of small programs, each with one job, that run on Cloudflare |
| 12 | Workers. A few face the internet. Almost all the rest can be reached only by the |
| 13 | Workers that are bound to them. Every service that keeps data keeps it in its own |
| 14 | database, and services learn what happened elsewhere from events instead of |
| 15 | calling each other to find out. |
| 16 | |
| 17 | This section is for developers: people building on g1t, contributing to it, |
| 18 | or running it themselves. It names the files, bindings and limits that |
| 19 | decide how g1t behaves, so you can read the code next to it. |
| 20 | |
| 21 | <Diagram name="platform-map" /> |
| 22 | |
| 23 | ## The layers |
| 24 | |
| 25 | | Layer | What is in it | Reached by | |
| 26 | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | |
| 27 | | **Clients** | Browsers, the [desktop](/guides/desktop/) and [phone](/guides/mobile/) apps, git, the [CLI](/guides/cli/), coding agents, [self-hosted runners](/guides/self-hosted-runners/), and visitors to apps deployed on g1t. | The internet | |
| 28 | | **Edge** | Four Workers with public routes: the site (`apps/web`), the API and MCP server (`apps/api`), the status page (`apps/status`) and the app dispatcher (`services/pages`). | Their hostnames | |
| 29 | | **Core** | Nineteen services, each a Worker with `workers_dev` off. Seventeen have no route at all; `telemetry` takes OTLP at `otel.g1t.sh` and `og` draws social cards at `og.g1t.sh`. | Service bindings from the Workers that name them | |
| 30 | | **Platform** | D1, Durable Objects, Queues, R2, KV, Artifacts for git, and Containers for sandboxes. | The one service that owns each, through its bindings | |
| 31 | |
| 32 | The edge does three things: it works out who is asking, enforces rate |
| 33 | limits, and turns a request into calls to the services that own the |
| 34 | answer. It keeps no state of its own. The services do the work and own the |
| 35 | data. |
| 36 | |
| 37 | ## Where each hostname goes |
| 38 | |
| 39 | | Hostname | Worker | Serves | |
| 40 | | ------------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------- | |
| 41 | | `g1t.sh` | `g1t` (`apps/web`) | The site, git over HTTPS, and the package registries, which it passes whole to `repos` and `packages` | |
| 42 | | `g1tusercontent.com` | `g1t` (`apps/web`) | Raw files, avatars and attachments, on a domain that never sees the session cookie | |
| 43 | | `api.g1t.sh`, `mcp.g1t.sh` | `g1t-api` (`apps/api`) | The REST API, the MCP server, OAuth, the runner protocol, and OTLP | |
| 44 | | `*.g1t.page` and custom domains | `g1t-pages` (`services/pages`) | Apps deployed on g1t | |
| 45 | | `otel.g1t.sh` | `g1t-telemetry` | OpenTelemetry from your software | |
| 46 | | `status.g1t.sh` | `g1t-status` (`apps/status`) | The status page, with a database of its own so it answers when the rest does not | |
| 47 | | `docs.g1t.sh` | `g1t-docs` (`apps/docs`) | These pages | |
| 48 | |
| 49 | `sudo.g1t.sh`, g1t's staff console, sits behind Cloudflare Access and is |
| 50 | not part of what you can call. |
| 51 | |
| 52 | ## Calls, events and ownership |
| 53 | |
| 54 | Three rules shape the code: |
| 55 | |
| 56 | - **A service owns its data.** Each of the sixteen D1 databases is bound |
| 57 | by exactly one Worker. To read another service's data, you call that |
| 58 | service. Three stores are deliberately shared, each with one writer: |
| 59 | the avatars KV, the custom domains KV, and the Actions cache bucket |
| 60 | ([Data and storage](/architecture/data/)). |
| 61 | - **Calls are for answers; events are for news.** When the site needs a pull |
| 62 | request, it calls `work`. When a push lands, `repos` does not call the |
| 63 | dozen services that care: it publishes `git.push`, and each of them gets |
| 64 | its own copy on its own queue ([Events](/architecture/events/)). |
| 65 | - **The viewer travels with the call.** The edge resolves the person or |
| 66 | token once, and passes the result to every service in the call's |
| 67 | arguments. Each service decides access itself with the same rules, |
| 68 | compiled in, rather than asking `identity` again |
| 69 | ([Identity and access](/architecture/identity/)). |
| 70 | |
| 71 | A call is an HTTP request over a service binding: `POST /rpc/<method>` |
| 72 | with a JSON body. An expected failure, such as "not found" or "not |
| 73 | allowed", comes back as a value, `{ "ok": false, "error": { "code", |
| 74 | "message" } }`, with status 200. Only something unexpected, a thrown error |
| 75 | or a busy store, becomes a non-200 status |
| 76 | ([Services and contracts](/architecture/services/)). |
| 77 | |
| 78 | ## Rust and TypeScript |
| 79 | |
| 80 | The services that hold accounts, repositories, work, events, money and the |
| 81 | API are written in Rust, compiled to WebAssembly with `worker-build`. The |
| 82 | web apps and the services built around Durable Objects and live rooms are |
| 83 | TypeScript. |
| 84 | |
| 85 | | Rust | TypeScript | |
| 86 | | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | |
| 87 | | `identity`, `repos`, `work`, `events`, `actions`, `packages`, `security`, `search`, `billing`, `integrations`, `webhooks`, and `apps/api` | `runner`, `deployments`, `projects`, `chat`, `artifacts`, `notify`, `telemetry`, `og`, `pages`, and `apps/web`, `apps/sudo`, `apps/status` | |
| 88 | |
| 89 | Both sides share their types through contracts: `crates/contracts` in Rust |
| 90 | and `packages/contracts` in TypeScript. Where the two must agree exactly, |
| 91 | such as the access rules and the scopes, a Rust test reads the TypeScript |
| 92 | file and fails if they differ. |
| 93 | |
| 94 | ## One codebase, two homes |
| 95 | |
| 96 | The same source runs on g1t.sh and in a [self-hosted |
| 97 | installation](/guides/self-hosting/). Each Cloudflare product a service |
| 98 | uses sits behind a port, and the self-hosted build binds an open |
| 99 | adapter in its place: bare repositories served by `git http-backend` for |
| 100 | Artifacts, any S3 store for R2, Mailpit for email. The service code does |
| 101 | not change. [Data and storage](/architecture/data/#ports-and-adapters) |
| 102 | shows each one. |
| 103 | |
| 104 | <Aside type="tip" title="Read the code next to this"> |
| 105 | Every unit g1t deploys is listed in `deploy/stack.jsonc`, with its language, its stage and what a self-hosted installation does with it. Each service's |
| 106 | `wrangler.jsonc` lists its bindings: its database, the services it calls, and the queues it reads. |
| 107 | </Aside> |
| 108 | |
| 109 | ## In this section |
| 110 | |
| 111 | <CardGrid> |
| 112 | <LinkCard |
| 113 | title="How a request is served" |
| 114 | href="/architecture/requests/" |
| 115 | icon="route" |
| 116 | description="The site and the API, from the first byte to Server-Timing." |
| 117 | /> |
| 118 | <LinkCard |
| 119 | title="Services and contracts" |
| 120 | href="/architecture/services/" |
| 121 | icon="boxes" |
| 122 | description="Every unit, what it owns, what it calls, and how calls work." |
| 123 | /> |
| 124 | <LinkCard title="Git" href="/architecture/git/" icon="git-branch" description="Where repositories live, the push path, caches and forks." /> |
| 125 | <LinkCard title="Events" href="/architecture/events/" icon="radio-tower" description="The bus, the log, fan-out, webhooks and following live." /> |
| 126 | <LinkCard |
| 127 | title="Work and the merge queue" |
| 128 | href="/architecture/work/" |
| 129 | icon="git-merge" |
| 130 | description="Work items, pull requests, checks, merging and the queue." |
| 131 | /> |
| 132 | <LinkCard |
| 133 | title="Actions, runners and sandboxes" |
| 134 | href="/architecture/compute/" |
| 135 | icon="cpu" |
| 136 | description="Workflow jobs, hosted and self-hosted, and what walls them in." |
| 137 | /> |
| 138 | <LinkCard title="Deployments and telemetry" href="/architecture/deployments/" icon="rocket" description="Apps on g1t.page, packages, and observability." /> |
| 139 | <LinkCard |
| 140 | title="Data and storage" |
| 141 | href="/architecture/data/" |
| 142 | icon="database" |
| 143 | description="Who owns what, migrations, and the ports that make self-hosting work." |
| 144 | /> |
| 145 | <LinkCard |
| 146 | title="Identity and access" |
| 147 | href="/architecture/identity/" |
| 148 | icon="key-round" |
| 149 | description="Credentials, the viewer, scopes, and where access is decided." |
| 150 | /> |
| 151 | <LinkCard |
| 152 | title="How g1t ships" |
| 153 | href="/architecture/shipping/" |
| 154 | icon="ship" |
| 155 | description="The monorepo, builds, staged deploys, and keeping these pages true." |
| 156 | /> |
| 157 | </CardGrid> |