A Letter from the Founders

The simplest projects often end up with the most complicated setups. A marketing site that should take an afternoon arrives with a bundler configuration, a content pipeline, and a dependency graph that looks like a map of the London Underground. None of that complexity ever reaches the visitor. It exists to serve the tooling.

ReeWeb is our answer to that: a static site generator that gets out of the way and then stays out of it.

The node_modules Problem

Every dependency is a promise. It promises to work the same way tomorrow, to have no breaking changes, to be maintained by someone who cares, and to never introduce a security vulnerability that sends you scrambling for an upgrade. And for a while, most of them keep that promise. But the ones that don't - the abandoned package, the silent API break, the license change that your legal team flags six months after you shipped - those cost more than the sum of all the ones that worked.

For a static site, the calculus is worse. You are generating HTML files. There is no user session to protect, no database connection to pool, no real-time state to manage. And yet the tooling around static sites has grown to resemble the tooling around real-time applications - the same bundler configuration, the same 2,000-line node_modules tree, the same fragile dependency graph that collapses the moment one transitive dependency decides to publish a breaking change.

We wanted to create a static site generator that didn't make that trade-off. ReeWeb has zero runtime dependencies. Every line of the template engine, the static site generator, and the dev server is written in plain TypeScript using Bun's native APIs. When you come back to a ReeWeb project a year later, it generates and renders exactly as it did the day you left it. There is no npm audit, no package you forgot you depended on, no node_modules folder that takes minutes to install.

Static by Default, Dynamic When Needed

Most projects don't need a database, a login system, or a real-time backend. They need fast HTML, well-organised templates, multi-language support, and static site generation that doesn't take longer than writing the content itself. We've built documentation sites, marketing pages, and multi-language landing pages for clients who had tried the full-stack approach and found it overkill - a server process they didn't need, a database they had to back up, a login screen their visitors never saw.

ReeWeb starts with those assumptions. You write .ree templates and markdown, get a fully rendered static site, and deploy it anywhere - a CDN, a VPS, a Raspberry Pi, or a simple static file host. There's no server process to keep running, no database connection to maintain, and no runtime to monitor. The output is flat HTML, served as fast as your CDN can deliver it.

But when your project outgrows static, ReeWeb doesn't force you to start over. The same template system, the same component library, and the same SSG pipeline work whether you're generating 10 pages or 10,000. And when you need the features that a static site can't provide - authentication, a database, form handling, an admin panel - you add a Reepolee application next to the site and use it as the data source, the way you would use a CMS. The site stays static, the templates and components you built keep working, and the same .ree skills apply on both sides. You grow into the parts you need, and never carry the ones you don't.

Bun Native

ReeWeb runs on Bun. Not because Bun is trendy - because it solves real problems that mattered to us when we were building this.

Bun replaces Node.js, the package manager, the bundler, and the test runner all in one binary. It understands TypeScript natively, so there is no tsconfig.json to configure and no build step for your generator scripts - they run as-is. bun install takes seconds, not minutes. The same runtime works on macOS, Linux, Windows, x86, and ARM. The same bun ssg command on a developer's laptop produces the same output in Workers Builds before Wrangler deploys it with Cloudflare Workers Static Assets.

We made a deliberate choice to base ReeWeb on Bun rather than on top of the Node.js ecosystem. Not because Node.js can't run a static site generator - it obviously can - but because using Bun as the foundation meant we could ship a tool that has zero npm dependencies at runtime. When you install ReeWeb, you get ReeWeb. Not ReeWeb plus a hundred packages you didn't choose.

Multi-Language by Design

We've lost track of how many clients came to us with a bilingual site where the "other language" was hidden behind a Google Translate widget in the corner, or served from a separate subdomain with a different design system, or simply marked as "coming soon" for months. Multi-language support is almost always an afterthought - a layer you add on top of a tool that was designed for one language, one market, one audience.

In ReeWeb, it's the other way around. Multi-language is built into the template engine, the SSG pipeline, and the URL structure from day one. We've generated bilingual sites for clients in markets where serving content in the wrong language is not an SEO problem - it's a credibility problem. A Slovenian visitor landing on an English-only page is not a user who will browse around until they find what they need. They leave.

ReeWeb handles this at the foundation. You write translation .json files next to your templates, and the static site generator does the rest: localized URLs (/about/ in English, /o-nas/ in Slovenian), hreflang links for Google, locale-aware date formatting, and fallback chains so a missing translation never leaves a blank on the page. You don't need a third-party translation service or a plugin. It's just how the tool works.

Familiar Templating

Ree templates look like HTML with a few extra tags - {= } for output, {#if} and {#each} for control flow, {#layout} and {#include} for composition. The template engine compiles to an async JavaScript function on first use and caches the result. In production, rendering is fast and predictable. In development, caching is off so changes appear immediately.

There is nothing novel about the syntax. That is the point. Drawing from Eta.js for output tags and from Svelte for control-flow blocks, we landed on something that feels familiar from the first time you open a .ree file. If you know HTML and a little JavaScript, you already know Ree. The implementation lives in lib/template_engine.ts and a handful of small modules under lib/template/ - plain TypeScript, readable, auditable, and yours to modify if you need it to behave differently.

The Stack We Settled On

Every layer here was picked once and then left alone. .ree templates compile to plain functions, so the rendering model stays inspectable and the markup stays yours. Multi-language is part of the pipeline rather than a plugin sitting on top of it. Tailwind v4 covers styling without starting a configuration debate. Bun's native APIs run the generator, the dev server, and the preview server, which keeps the whole pipeline on one runtime and one mental model.

Nothing on that list is clever, and we were not trying to be. We wanted parts with stable APIs that would still behave the same way long after we stopped paying attention to them.

Who ReeWeb Is For

If you are building a marketing site, a documentation set, or a bilingual landing page, ReeWeb is sized for exactly that work. It assumes you want fast HTML, tidy templates, and translations that were planned rather than retrofitted - and that you would rather not operate an application framework to produce a folder of static files.

If you have ever counted the packages required to generate HTML and struggled to justify the number, this one was written for you.

The Reepolee Team