FULL-STACK BUILD SYSTEM AND RENDERING ENGINE Made with HyperBricks

How HyperBricks works

HyperBricks is a native full-stack build system with an integrated rendering engine for hypermedia web applications. You configure and connect components using a declarative, YAML-based language. HyperBricks renders and serves HTML pages, fragments, and application endpoints. It brings the application lifecycle together in one project: compose, build, serve, export, and deploy. HyperBricks provides these workflows through a single command-line executable that also runs the application server.

HyperBricks includes a development interface with three sections: Dashboard, Spaces, and Errors.

Features

Hybrid rendering
Choose per page or fragment whether to serve cached output or render it dynamically.
Backend logic
Integrate native Go plugins and server-side JavaScript through components.
Frontend assets
Bundle JavaScript, TypeScript, and CSS with the integrated esbuild component.
Static export
Export your configured application as a ready-to-deploy ZIP archive of rendered HTML and assets.
Spaces
Create inheriting pages with source-defined editable fields for content editing and localization.
Deployment
Build and push applications, compile native Go plugins, and manage remote deployments through dedicated local and remote web interfaces.

Beta software — Features, configuration, and APIs may change. Read the project status.

HyperBricks Workflow

APPLICATION LIFECYCLE

INIT New project Create a module from a starter.
DEVELOP Develop and Iterate Run, inspect, and refine the application.
DEPLOY Choose how to deploy Prepare the application for static or dynamic hosting.
hyperbricks init-starter get hello-world -m demo

EXAMPLES

Compose a page from reusable components

Components define what HyperBricks renders. Templates define the HTML. Values supply content or the output of other components. Use inherit to reuse a component and override the values that differ. Choose an example below and switch between its YAML and rendered HTML.

Define a reusable text component, then include it in a page with inherit. HyperBricks renders the result as HTML.

hero.hyperbricks.yaml yaml
# Text: value is required and emitted unchanged, without HTML escaping.
# Use trusted configuration content; bind visitor input through a Go HTML template.
example_text:
  - type: text
  - value: Your next adventure starts here. # Required text.
  - enclose: <p>|</p> # Optional wrapper.

home:
  - type: hypermedia
  - route: index
  - title: Hello HyperBricks
  - content:
      - inherit: example_text

Pass a title and rendered Markdown into a template through values. Reuse the same template component in a full page and an HTML fragment.

page.hyperbricks.yaml yaml
# Template: choose inline or template.file for meaningful output.
# No individual source field is schema-required; the selected file must exist.
# Scalar data and renderable children both mount under values.
example_template:
  - type: template
  - inline: |
      <article>
        <h2>
          {{.title}}
        </h2>
        {{.body}}
      </article>
  - querykeys: [] # Optional; this template exposes no request query parameters.
  - values: # Optional; supply only keys that the template actually uses.
      title: Latest updates
      body:
        - type: markdown
        - content: |
            Our spring collection is here. Discover new ideas for your next project.

home:
  - type: hypermedia
  - route: index
  - title: Hello HyperBricks
  - htmltag: '<html lang="en">'
  - head:
      - type: head
      - charset:
          - type: html
          - value: '<meta charset="utf-8">'
      - meta:
          viewport: width=device-width, initial-scale=1
  - content:
      - inherit: example_template
      - enclose: '<main>|</main>'

intro_fragment:
  - type: fragment
  - route: fragments/intro
  - content:
      - inherit: example_template

This Fragment example returns a fixed booking-confirmation message without a page wrapper. It performs no booking action. Its route and static path are adapted for the demo below.

fragment.hyperbricks.yaml yaml
# Fragment: no additional schema-required fields; children provide its output.
# A routed fragment returns replaceable HTML without a document wrapper.
example_fragment:
  - type: fragment
  - route: examples/status.html # Adapted route for the landing demo.
  - static: examples/status.html # The static demo uses the same URL.
  - nocache: true # Optional; bypass rendered-output caching for fresh status.
  - response: # Optional browser response settings.
      headers:
        Cache-Control: no-store
  - content:
      - type: html
      - value: |
          <p id="status" data-fragment-example="ready">
            Your booking request has been received.
          </p>

This API Fragment Render example lists items from your service. Set EXAMPLE_API_URL to an endpoint returning an items array with title fields. The template also checks upstream Status for feedback; an API error does not automatically change the browser response status.

api.hyperbricks.yaml yaml
# API fragment render: required endpoint and method.
# route is conditional for exposing an independently requested browser URL.
# Always calls the upstream API; unlike nested api_render it owns a route.
release_feed:
  - type: api_fragment_render
  - route: fragments/releases # Adapted demo route.
  - endpoint: {env: EXAMPLE_API_URL} # Required; configure your item-list API.
  - method: GET # Required upstream HTTP method.
  - headers: # Optional upstream headers, not browser response headers.
      Accept: application/json
  - querykeys: [] # Optional; forward no browser query values to this API.
  # The documented item-list template adds explicit status and empty feedback.
  - inline: |
      <section aria-label="Item list">
      {{if eq .Status 200}}
        <ul>
        {{range .Data.items}}
          <li>{{.title}}</li>
        {{else}}<li>No items available.</li>{{end}}
        </ul>
      {{else}}
        <p role="status">The item list is temporarily unavailable.</p>
      {{end}}
      </section>
  - response:
      headers:
        Cache-Control: no-store

The CSS bundle follows the Esbuild example in the type guide. Supply resources/css/example.css and mount the component in the page head. Build caching is separate from page caching.

assets.hyperbricks.yaml yaml
example_styles:
  - type: esbuild
  - entry: # Required CSS source reference.
      path: {base: resources, path: css/example.css}
  - outfile: # Required generated CSS output reference.
      path: {base: static, path: css/example.css}
  - cache: true
  - minify: true
  - fingerprint: true
  - enclose: <link rel="stylesheet" href="|">

# Mount the documented CSS component in a page head so it runs.
assets_page:
  - type: hypermedia
  - route: assets
  - title: CSS bundle
  - htmltag: '<html lang="en">'
  - head:
      - type: head
      - charset:
          - type: html
          - value: '<meta charset="utf-8">'
      - meta:
          viewport: width=device-width, initial-scale=1
      - styles:
          - inherit: example_styles
  - content:
      - type: html
      - value: '<main><h1>CSS bundle example</h1></main>'
The CSS entry resources/css/example.css
example.css css
:root {
  --example-accent: #0e7490;
  --example-text: #26323d;
}

body {
  margin: 0;
  color: var(--example-text);
  font-family: system-ui, sans-serif;
  line-height: 1.6;
}

main {
  width: min(60rem, calc(100% - 3rem));
  margin: 5rem auto;
}

h1 {
  color: var(--example-accent);
}

This page uses the inherited-page pattern from the type guide with an editable heading. The source owns the template and editing rules. The Space overrides its route, title, language, and content.

spaces.hyperbricks.yaml yaml
imports:
  - spaces/site_source/index.hyperbricks.yaml

site_source:
  - type: hypermedia
  - head:
      - type: head
      - metadata:
          - type: html
          - value: '<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">'
  - content:
      - type: template
      - inline: '<main><h1>{{.heading}}</h1></main>'
      - values:
          heading: Latest updates
      - editable:
          heading: {type: text, label: Heading, required: true, max: 120}
The Space instance spaces/site_source/en.hyperbricks.yaml
en.hyperbricks.yaml yaml
site_en:
  - inherit: site_source
  - route: en
  - title: English edition
  - htmltag: '<html lang="en">'
  - content:
      - type: template
      - values:
          heading: Coastal journal

The managed index imports this instance. Enable Spaces writes in development to edit its declared heading. Saving changes the source files; publishing needs a build or deployment.

FRAGMENT DEMO

Request an HTML fragment

Request the configured fragment and insert its HTML into this page. The response contains a fixed example message, with no backend action.

Open the raw HTML
GET /examples/status.html Ready

The fragment will appear here.

Live mode renders the route. A static export serves the generated HTML file.

The browser side HTML + vanilla JavaScript
client.html markup
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Request a HyperBricks fragment</title>
<main>
  <button id="request-fragment" type="button">Request the fragment</button>
  <div id="fragment-result" aria-live="polite"></div>
</main>
<script type="module">
  const button = document.querySelector('#request-fragment');
  const result = document.querySelector('#fragment-result');
  button.addEventListener('click', async () => {
    button.disabled = true;
    result.textContent = 'Requesting the fragment…';
    try {
      const response = await fetch('/examples/status.html');
      const errors = response.headers.get('X-Hyperbricks-Render-Error-Count');
      if (!response.ok || (errors !== null && errors !== '0')) {
        throw new Error('The fragment could not be rendered.');
      }
      result.innerHTML = await response.text();
    } catch {
      result.textContent = 'The fragment is unavailable. Please try again.';
    } finally {
      button.disabled = false;
    }
  });
</script>
</html>

HOW RENDERING WORKS

From configuration to HTML

HyperBricks resolves each browser or HTMX request to a route. It checks whether it can reuse cached output. When rendering is needed, it checks access and runs the configured components. The diagram shows how the request reaches a response.

  1. 01

    Routing and caching

    HyperBricks resolves the request to a hypermedia, fragment, or api_fragment_render route. Development mode renders fresh. Live mode can return an eligible cached response, skipping component rendering and integrations. Guarded routes bypass the cache.

    Route · Cache
  2. 02

    Access and rendering

    For requests that need rendering, HyperBricks checks the optional route guard first. A denial returns immediately. If allowed, the engine renders the configured component tree and combines child output in YAML sequence order. Templates, API calls, scripts, and plugins run where they are configured in that tree.

    Guard · Component graph
  3. 03

    Output and response

    HyperBricks selects the composed output or an HTTP response supplied by a native plugin. It stores eligible live output with its cache metadata and writes the status, headers, cookies, and body. A native plugin stream starts after the headers are written. The client handles the response.

    Status · Headers · Body

HyperBricks Runtime

hit

render

denied

allowed

cacheable

uncached

HTTP

Client Request

Resolve Route

Check Cache

Reuse Cache

Check Guard

Render Graph

Component Work

Select Output

Store Output

Write Response

Handle Response

Principles

These principles guide the design and development of HyperBricks.

Keep developers in the loop

Agents work through HyperBricks' schema-enforced, human-readable declarative architecture, so changes remain visible as application design rather than opaque generated boilerplate.

Extensibility

HyperBricks can be extended with components, integrations, plugins, and workflows, adding new capabilities without changing the core.

Composability through modularity

Applications should be assembled from reusable components that can be combined while keeping their relationships, boundaries, and source ownership clear.

Focus on design

Structure, interaction, visual composition, and responsive behavior should remain first-class concerns throughout development.

Separate domain logic from structure

Application structure and presentation should remain distinct from business rules and external integrations, while still working together as one application.

FAQ

Frequently asked questions

What belongs in YAML?

Use YAML to define routes, compose components and supply their settings and values. Use inherit to reuse a component and override what differs. Component sequences preserve the order of child output.

What belongs in an HTML template?

Templates define your HTML markup. They receive values from the component configuration, including rendered child components. Use Go html/template expressions for loops and conditions, CSS for styling and browser JavaScript for interaction.

Where does application logic run?

HyperBricks YAML is declarative, not a scripting language. It selects, configures and connects components that execute existing logic. Templates can contain presentation logic such as conditions, loops and function calls, using Go template syntax. HyperBricks renders HTML templates with Go html/template. For application logic, use server-side JavaScript, native Go plugins or external services called through API components.

How do pages and fragments share content?

Define a reusable component and inherit it from both a hypermedia page and a fragment. Override values where the output should differ. The page supplies the full document; the fragment supplies HTML that a browser library can insert into an existing page.

How does Spaces use the page composition?

A Space inherits a source page and supplies its own route, metadata and content. The source declares which fields Spaces can edit. Saving writes project files; it does not publish the site.

When should I use static export?

Use static export when your site can be served as rendered HTML and assets. API data is captured when the export runs. Keep a HyperBricks server running for routes that need request-time API calls or backend logic.

BETA STATUS

HyperBricks is under active development. Features, configuration, and APIs may change as the project evolves. The project is released under the MIT License and provided “as-is,” without any warranties or guarantees.