A framework with a point of view

Learn Amber's Way.

Amber is deliberately opinionated about both the experience of building software and the shape of the code. The values tell us how to work together. The coding beliefs make those values concrete in every application.

Chibi Amber standing confidently and giving a peace sign

Shared values

How we build together.

Productivity, performance, and happiness describe what Amber should make possible. Humility, respect, and trust describe the community required to sustain it.

01

Productivity.

Use conventions, generators, and one coherent application structure to remove routine decisions. The goal is to move from an idea to useful software without spending the first week assembling a framework.

02

Performance.

Build on Crystal's type system, native compilation, concurrency, and macros. Performance should be part of the framework's architecture—not a tax the application team pays after the product succeeds.

03

Happiness.

Make everyday web development simple, comfortable, and understandable. Clear errors, readable defaults, useful diagnostics, and fast feedback protect the attention that developers need for their actual product.

04

Humility.

Amber is not the center of the universe. Borrow ideas that have been tested elsewhere, acknowledge incomplete work, invite correction, and stay open to better answers from Crystal and the wider web community.

05

Respect.

Treat contributors and users as people whose time matters. Document the path, preserve stable references, explain breaking changes, and design defaults that do not surprise the next person maintaining the application.

06

Trust.

Build code and processes that another developer—or coding agent—can understand and safely extend. Share context, keep responsibilities explicit, and let capable collaborators drive when they are closest to the problem.

Coding beliefs

The framework should teach the application.

An Amber codebase should reveal its intent without archaeology. A route names the request path, a controller coordinates the work, respond_with declares the available representations, ECR owns HTML, and local browser assets finish the experience.

Belief 01

Controller boundary

One action.
Honest representations.

HTML and JSON are two representations of the same resource, not two excuses to repeat the application logic. Load the data once. Use a Rails-inspired respond_with block to state exactly what the action can return. Amber selects a representation from the request's Accept header or extension and returns 406 Not Acceptable when none matches.

HTML renders the ECR view and application layout JSON serializes the same resource explicitly Tests exercise each public representation
Open this action's JSON representation
src/controllers/articles_controller.cr
class ArticlesController < ApplicationController
  def show
    article = ArticleCatalog.fetch(params["slug"])

    respond_with do
      html { render("show.ecr") }
      json { article.to_json }
    end
  end
end
GET /articles/amber-way
Accept: text/html
ECR + layout GET /articles/amber-way
Accept: application/json
JSON

Belief 02

Application structure

The filesystem is part of the documentation.

Amber CLI generates one predictable home for each responsibility. This is the supported V2 web shape—not a suggestion that every application invents again.

my_app/
my_app/
├── config/
│   ├── application.cr
│   ├── routes.cr
│   └── environments/
├── public/
│   ├── css/app.css
│   └── js/app.js
├── spec/
│   └── controllers/
├── src/
│   ├── my_app.cr
│   ├── controllers/
│   │   ├── application_controller.cr
│   │   └── home_controller.cr
│   └── views/
│       ├── home/index.ecr
│       └── layouts/application.ecr
└── shard.yml
  1. 01
    config/routes.cr

    Maps an HTTP method and path to a controller action through an explicit pipeline.

  2. 02
    src/controllers/

    Loads resources, applies request policy, and declares the available response formats.

  3. 03
    src/views/

    Owns the server-rendered HTML, reusable partials, and the shared document layout.

  4. 04
    public/

    Serves local CSS, JavaScript modules, fonts, and images without a front-end build step.

  5. 05
    spec/

    Verifies the request contract at the same boundary a browser or API client uses.

Jobs, mailers, channels, models, and schemas follow the same rule: focused directories with stable generator destinations. See the complete generated web template.

Belief 03

HTML boundary

Views should look like the document they create.

ECR keeps HTML visible, lets Crystal locals cross the rendering boundary, and makes layout composition explicit. Dynamic values are escaped; only framework-rendered template content is inserted as trusted markup.

src/views/articles/show.ecr
<article class="article-shell">
  <p class="eyebrow">Field note</p>
  <h1><%= escape_html(article[:title]) %></h1>
  <p><%= escape_html(article[:summary]) %></p>

  <%= render(
    partial: "articles/_meta.ecr"
  ) %>
</article>
src/views/layouts/application.ecr
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport"
      content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/css/app.css">
  </head>
  <body>
    <%= content %>
    <script type="importmap">
      {"imports":{"app":"/js/app.js"}}
    </script>
    <script type="module">import "app";</script>
  </body>
</html>
Renderrender("show.ecr") Partialrender(partial: "articles/_meta.ecr") No layoutrender("card.ecr", layout: false) Escape valuesescape_html(value)
Read the complete ECR view guide

Belief 04

Front-end baseline

Use the web platform before adding a toolchain.

A complete front end does not require an external library. Start with semantic HTML from ECR, locally served CSS, standard JavaScript modules, and a browser-native import map. Add dependencies only when the application has earned the extra release and security surface.

HTML

ECR renders the first useful screen.

Routes work without JavaScript, metadata stays in the layout, and progressive enhancement begins from a real document.

CSS

Tokens and components stay local.

Custom properties, Grid, Flexbox, container-aware responsive rules, and reduced-motion fallbacks cover the common system.

ES modules

Import names stay stable.

The import map points a bare name such as app at a local module. No npm install, bundle, or CDN is required.

This website is the proof

The page you are reading follows the path it recommends.

  • Amber controller and respond_with
  • ECR views and partials
  • One local design-system stylesheet
  • One local ES module resolved by an import map
  • No front-end framework, bundler, asset CDN, analytics, or application cookies
Build the native import-map baseline

Belief 05

Measured performance

A number without its workload is not a benchmark.

The July 17, 2026 Amber V2 performance lab measured a mixed, 1,000-route application—not a static-response best case. The current JSON path sustained a median 21,795 whole HTTP requests per second on the smallest one-vCPU target.

Hosted median 21,795 req/s

Current Amber JSON params · HTTP/1.1 keep-alive

Target
1 vCPU · 512 MB class
Application
1,000 mixed routes
Load
16 connections · separate host
Protocol
HTTP/1.1 keep-alive
Trials
7 rotating repetitions
Integrity
0 socket or non-2xx errors

What this does not claim: it is not a static-endpoint estimate, a cross-framework ranking, a production capacity promise, or an SLA for every Amber application. It is a dated result for a documented workload. The full seven-variant matrix delivered 18,728,053 successful responses; application code, hardware, proxies, databases, and traffic shape will change your result.

Opinionated by design

Own the path.
Shrink the attack surface.

Amber should provide a coherent first-party answer wherever the framework can responsibly do so. Every external dependency adds another project, release process, and delivery chain an application must trust. Bringing proven responsibilities into the framework reduces that exposure and makes the supported path easier to test as one system.

Fewer dependencies reduce supply-chain and disruption risk; they do not eliminate it. First-party code still requires review, maintenance, release discipline, and clear security boundaries.

01

Defaults with a point of view

Choose a complete convention for the common path, document it end to end, and make extension a deliberate decision instead of setup homework.

02

Dependencies must earn their place

Prefer first-party capabilities when Amber can own their quality and compatibility. Add third-party packages when they provide clear value that the framework should not duplicate.

03

Responsibilities stay explicit

Personify major architectural boundaries as crew members; keep focused products and systems—such as Asset Pipeline—named for the work they perform.