Skip to content

Engineering · 4 min read

Tech stack

What we reach for by default, and why: boring proven tools, one clear owner for the data, and each product free to pick the stack that fits it.

Flagon doesn't have one tech stack. Each product picks its own, because each product is its own thing with its own small team, and that team is the one living with the choice every day. What the company does have is a set of defaults and a couple of rules that hold everywhere. This page is those, with the stacks we actually run as worked examples. None of it is exotic. That's the point: we spend our interesting-technology budget on the product, not the plumbing, exactly as how we build describes.

What we reach for by default

  • TypeScript for anything with a UI. The types pay for themselves the first time you rename a field, and they make whole categories of test unnecessary.
  • React for interfaces, rendered on the server where we can, so the first paint is real content and not a spinner.
  • A written contract at every boundary. When one piece calls another over the network, the shape of that call lives in shared types or an OpenAPI document, generated from the code where possible, so the two sides can't quietly disagree about what an endpoint returns.
  • A managed platform over servers we babysit. Vercel and Cloudflare today. Every machine we don't have to patch is one fewer thing that pages someone at 2am.
  • The language that fits the job, not the one that's fashionable this year, and not the one a previous product happened to use.

These are defaults, not mandates. A product team can choose differently, and sometimes should. What it needs is a reason it can say out loud, and an answer to the question from how we build: who's on call when this breaks in a way nobody has seen before?

One thing owns the data

This is the rule that holds across every product, whatever it's written in. The data has exactly one owner, and that owner is the only thing that touches it. The web front end holds none of it; when it needs something real, it asks.

One rule holds the architecture together

Whatever owns the data is the only thing that reads or writes it. If you're reaching around it, stop. That single boundary is what keeps a system honest as it grows, because the rules live in one place instead of two.

How that looks varies a lot by product, which is fine. The boundary is what matters, not the shape on either side of it.

The stacks we run today

g1t

g1t is Rust and TypeScript on Cloudflare Workers. The site is server-rendered React on a Worker, and it holds no data. Everything that isn't a web UI is written in Rust: the REST API and MCP server, and a set of services (accounts and workspaces, repositories, issues and pull requests, events, and the runner that starts sandboxes), each its own Worker with its own database. The services call each other through service bindings and react to each other through events, so each one owns its slice of the data outright. Acceptance checks and g1t's own agents run in sandboxes on Cloudflare Containers. The REST API and the MCP server sit over the same operations, described by one OpenAPI document, so there's one contract and two ways in.

This website

The company site you're reading is the simplest thing that works: a Next.js App Router app in TypeScript and React, styled with Tailwind CSS v4, deployed on Vercel. The handbook and the blog are MDX files in the repo, rendered with next-mdx-remote. There's no database at all. The content is the files, so changing a handbook page is a pull request like any other change, and the data owner is git.

The two look nothing alike, and that's the model working. A forge for thousands of agents and a company website have different jobs, so they got different tools.

How to read this page later

Versions and libraries drift, and this page doesn't try to track them. The real answer to "what exactly are we on" is in each product's own repo: its lock files, its Cargo.toml or package.json, and its README, which is the source of truth for how that product is built (more on that in project structure). What shouldn't drift is the shape: boring defaults, a written contract at each boundary, and one owner for the data. If a proposed change breaks one of those, it needs a good story for why.