> For the complete documentation index, see [llms.txt](https://azutopia.gitbook.io/azu/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://azutopia.gitbook.io/azu/readme.md).

# Overview

Typed request and response contracts, segment-tree routing and built-in real-time for Crystal web apps.

<img src="https://github.com/user-attachments/assets/15b65c4e-6754-4b58-a9b5-3373a69d0244" alt="azu-readme-cover" width="900">

## Azu Web Framework Overview

{% hint style="info" %}
Azu is a strongly typed web framework for Crystal. Every endpoint declares the request contract it accepts and the response it returns: the compiler checks the types, and Azu validates each request against its contract before your code runs. Routing is a tree of path segments, and WebSocket channels, pub/sub, presence and Spark live views are built in.
{% endhint %}

***

### Quickstart: The Minimal Type-Safe Endpoint

Azu replaces untyped params hashes with explicit **Request Contracts** and **Response Objects**.

{% code title="src/hello.cr" %}

```crystal
require "azu"

# 1. Request contract: typed fields, built from the query string, form or JSON body
struct HelloRequest
  include Azu::Request

  getter name : String = "World"
end

# 2. Response object: turns data into the body
struct HelloResponse
  include Azu::Response

  def initialize(@name : String)
  end

  def render : String
    "Hello, #{@name}!"
  end
end

# 3. Endpoint: accepts a HelloRequest, must return a HelloResponse
struct HelloEndpoint
  include Azu::Endpoint(HelloRequest, HelloResponse)

  get "/hello"

  def call : HelloResponse
    HelloResponse.new(hello_request.name)
  end
end

# 4. Configure and start the application
module MyApp
  include Azu

  configure do |config|
    config.port = 3000
    config.env = Azu::Environment::Development
  end
end

MyApp.start [
  Azu::Handler::Logger.new,
  Azu::Handler::Rescuer.new,
] of HTTP::Handler
```

{% endcode %}

{% code title="Terminal" %}

```bash
crystal run src/hello.cr
curl "http://127.0.0.1:3000/hello"           # Hello, World!
curl "http://127.0.0.1:3000/hello?name=Ada"  # Hello, Ada!
```

{% endcode %}

* `hello_request` is the `HelloRequest` Azu built for this request. Reading a field the contract does not declare, or returning anything but a `HelloResponse`, is a compile error.
* The handler array is used exactly as given. `MyApp.start` with no argument uses the default stack: request id, logging, error pages, security headers and static files.
* The project setup (`shard.yml`, a test, templates) is in [Getting started](/azu/start-here/getting-started.md). To have a project generated for you, see [Get started in 5 minutes](https://github.com/azutoolkit/azu#get-started-in-5-minutes).

### Design pillars

| Pillar                   | You write                                                 | Azu enforces                                                                                                                                                                                                                    | When                         |
| ------------------------ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| **Typed contracts**      | `include Azu::Endpoint(Req, Res)`                         | `call` returns a `Res`. The request accessor, named after its type (`hello_request` for `HelloRequest`), has only the fields that type declares.                                                                                | Compile time                 |
| **Validation**           | `validate name, size: 2..30`                              | A missing or mistyped field answers `400`. A broken rule answers `422` with an [RFC 7807](https://www.rfc-editor.org/rfc/rfc7807) document listing each failing field. Either way `call` never runs.                            | Every request, before `call` |
| **Segment-tree routing** | `get "/users/:id"`, or `app.routes { ... }`               | Static, `:param` and `*wildcard` segments, plus `scope` and `mount`. Methods and paths must match exactly, and a duplicate route fails at boot. A static route is found without allocating, and there is no path cache to fill. | Boot and every request       |
| **Spark live views**     | `Azu::Spark::Component` with `prop`, `state`, `event def` | The browser can trigger only `event def` methods, and their arguments arrive as the declared types. Joining needs a signed, expiring token. The server sends back only the HTML that changed.                                   | Every event                  |
| **Opt-in extras**        | `require "azu/dev"`, `"azu/cql"`, `"azu/testing"`         | `require "azu"` alone does not load them. Core reaches optional subsystems through `Azu::Instrumentation`, which costs one nil check when nothing subscribes.                                                                   | Compile time                 |

Details: [Endpoint](/azu/reference/endpoint.md), [Request](/azu/reference/request.md), [Validate requests](/azu/how-to-guides/validate-requests.md), [Router](/azu/reference/router.md), [Spark live views](/azu/concepts/spark-live-views.md), [Performance design](/azu/concepts/performance-design.md). This page has no speed figures. The reproducible suite and its method are in [Benchmarks](https://github.com/azutoolkit/azu/blob/master/benchmark/README.md).

### Request lifecycle

```mermaid
flowchart TD
    client["Client"] -- HTTP --> server["HTTP::Server"]
    server --> chain["Handler chain<br/>the array given to start, outermost first"]
    chain --> router{"Segment-tree router<br/>method + path"}
    router -- no route --> notfound["404"]
    router -- WebSocket upgrade --> channel["Channel"]
    router --> build{"Build contract"}
    build -- field missing or wrong type --> bad["400"]
    build --> validate{"Validate rules"}
    validate -- a rule fails --> invalid["422 + field errors"]
    validate --> handle["call : Response<br/>your code"]
    handle --> body["render → body"]
    body --> back["Handler chain, in reverse → client"]
```

Step by step, with a program that prints the order: [Request lifecycle](/azu/concepts/request-lifecycle.md). Components and the handler chain: [Architecture overview](/azu/concepts/overview.md).

### Contracts vs params hashes

```crystal
struct SignupRequest
  include Azu::Request

  getter name : String
  getter age : Int32

  validate name, size: 2..30, message: "must be 2 to 30 characters"
  validate age, gte: 18, message: "must be 18 or older"
end
```

| Situation                                 | Untyped params hash                            | Azu contract (`SignupRequest`)                                                                                          |
| ----------------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `age` is missing                          | `nil`, or an exception where the code reads it | `400` `Missing required property: 'age'.` before `call`                                                                 |
| `age=abc` (form) or `"age": "abc"` (JSON) | A conversion you write, in every handler       | `400` before `call`                                                                                                     |
| `name=A&age=12`                           | Checks you write and keep in sync              | `422` with `errors: {name: [...], age: [...]}` before `call`                                                            |
| `age` used as a number                    | `params["age"].to_i` at each use               | `signup_request.age` is an `Int32`                                                                                      |
| Misspelled field in your code             | `nil` at runtime                               | Compile error                                                                                                           |
| API description                           | Written and maintained by hand                 | `Azu::OpenAPI` builds an OpenAPI 3.1 document from the contracts ([OpenAPI](/azu/reference/openapi.md))                 |
| Tests                                     | Raw HTTP requests                              | `Azu::Testing::Client` drives the real handler chain and router without a socket ([Testing](/azu/reference/testing.md)) |

Error bodies follow the `Accept` header: problem JSON, JSON, HTML or text. See [Handle validation errors](/azu/how-to-guides/handle-validation-errors.md) and [Contracts](/azu/concepts/contracts.md).

### Choosing a real-time primitive

| Primitive                                                         | Transport                                              | State lives in                               | Across nodes                                                                | Use it for                                                |
| ----------------------------------------------------------------- | ------------------------------------------------------ | -------------------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------- |
| [`Azu::Channel`](/azu/reference/channel.md)                       | WebSocket, both directions                             | One instance per connection                  | Broadcast through `Azu::PubSub::Redis`                                      | Your own message protocol: chat, games, device feeds      |
| [`Azu::PubSub`](/azu/how-to-guides/broadcast-messages.md)         | In process. `PubSub::Redis` between processes          | Nothing: it is a topic bus                   | `PubSub::Redis`. Messages published while a subscriber reconnects are lost  | Fan-out to channels and components                        |
| [`Azu::Presence`](/azu/reference/presence.md)                     | Join and leave diffs on `presence:<topic>`, via PubSub | `Store::Memory`, or Redis hashes             | `Store::Redis`. A dead node's users leave after `ttl`                       | Who is in a room or document right now                    |
| [`Azu::Response::EventStream`](/azu/reference/streaming.md) (SSE) | HTTP, server to browser                                | The stream's fiber                           | `EventSource` reconnects to any instance with `Last-Event-ID`               | Notifications, progress, feeds                            |
| [`Azu::Spark::Component`](/azu/concepts/spark-live-views.md)      | WebSocket. Browser events in, HTML diffs out           | The component, on the server, per connection | State marked `persist: true` comes back from a signed snapshot on reconnect | Interactive server-rendered UI without writing JavaScript |

A Spark live view, complete:

```crystal
class Counter < Azu::Spark::Component
  mountable

  prop label : String = "Clicks"
  state count : Int32 = 0

  event def increment(by : Int32 = 1) : Nil
    self.count += by
  end

  def render
    div class: "counter" do
      h2 "#{label}: #{count}"
      button "+1", **spark_click(:increment)
      button "+10", **spark_click(:increment, by: 10)
    end
  end
end
```

Multi-node setup: [Real-time across processes](/azu/how-to-guides/scale-horizontally.md#real-time-across-processes). Wire protocol, reconnects and patching: [Spark client](/azu/reference/spark-client.md).

### Documentation map

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Tutorials</strong></td><td>Learn by building, in order. Start with a validated endpoint in about 15 minutes.</td><td><a href="/azu/start-here/getting-started.md">Getting started</a></td></tr><tr><td><strong>How-to guides</strong></td><td>One task per page: endpoints, validation, templates, real-time, data, deployment.</td><td><a href="/azu/how-to-guides/create-endpoint.md">Create an endpoint</a></td></tr><tr><td><strong>Reference</strong></td><td>Exact signatures, options, defaults and behavior.</td><td><a href="/azu/reference/endpoint.md">Endpoint</a></td></tr><tr><td><strong>Concepts</strong></td><td>Why Azu works the way it does, and how the parts fit.</td><td><a href="/azu/concepts/overview.md">Architecture overview</a></td></tr></tbody></table>

Also: [Examples](/azu/start-here/examples.md) (runnable apps in `playground/`) · [Everything in the box](/azu/start-here/features.md) (every feature, with its guide) · [FAQ and troubleshooting](/azu/start-here/faq.md) · [Migrate to 0.6](/azu/start-here/migrate-to-0.6.md) · [Breaking changes](/azu/reference/breaking-changes.md)

### Tutorials

1. [Getting started](/azu/start-here/getting-started.md): an endpoint with a validated contract, a page, a test and the dev dashboard, in about 15 minutes.
2. [Building a user API](/azu/tutorials/building-a-user-api.md): a complete JSON CRUD API.
3. [Working with databases](/azu/tutorials/working-with-databases.md): CQL models, migrations and queries.
4. [Adding WebSockets](/azu/tutorials/adding-websockets.md): a chat channel with pub/sub.
5. [Building live components](/azu/tutorials/building-live-components.md): server-rendered views that update in place.
6. [Testing your app](/azu/tutorials/testing-your-app.md): endpoints, contracts, channels and components.
7. [Deploying to production](/azu/tutorials/deploying-to-production.md): configuration, secrets and a running service.

### How-to guides

| Area             | Guides                                                                                                                                                                                                                                                                                              |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Endpoints        | [Create an endpoint](/azu/how-to-guides/create-endpoint.md) · [Handle parameters](/azu/how-to-guides/handle-parameters.md) (path, query, form, JSON) · [Return different formats](/azu/how-to-guides/return-different-formats.md)                                                                   |
| Apps and APIs    | [Mount an app under a prefix](/azu/how-to-guides/mount-an-app.md) · [Run several apps in one process](/azu/how-to-guides/run-several-apps.md) · [Publish your OpenAPI document](/azu/how-to-guides/publish-openapi.md)                                                                              |
| Validation       | [Validate requests](/azu/how-to-guides/validate-requests.md) · [Handle validation errors](/azu/how-to-guides/handle-validation-errors.md)                                                                                                                                                           |
| Files            | [Handle file uploads](/azu/how-to-guides/handle-file-uploads.md) · [Validate file types](/azu/how-to-guides/validate-file-types.md)                                                                                                                                                                 |
| Errors           | [Handle errors gracefully](/azu/how-to-guides/handle-errors-gracefully.md) · [Create custom errors](/azu/how-to-guides/create-custom-errors.md) · [Debug exceptions](/azu/how-to-guides/debug-exceptions.md)                                                                                        |
| Middleware       | [Create custom middleware](/azu/how-to-guides/create-custom-middleware.md) · [Add logging](/azu/how-to-guides/add-logging.md) · [Use sessions](/azu/how-to-guides/use-sessions.md) · [Protect forms and APIs](/azu/how-to-guides/protect-forms-and-apis.md)                                         |
| Templates        | [Render HTML templates](/azu/how-to-guides/render-html-templates.md) · [Enable hot reload](/azu/how-to-guides/enable-hot-reload.md) · [Localize your app](/azu/how-to-guides/localize-your-app.md)                                                                                                  |
| Real-time        | [Create a WebSocket channel](/azu/how-to-guides/create-websocket-channel.md) · [Broadcast messages](/azu/how-to-guides/broadcast-messages.md) · [Build a live component](/azu/how-to-guides/build-live-component.md) · [Stream server-sent events](/azu/how-to-guides/stream-server-sent-events.md) |
| Database         | [Define a schema](/azu/how-to-guides/define-schema.md) · [Create models](/azu/how-to-guides/create-models.md) · [Run migrations](/azu/how-to-guides/run-migrations.md) · [Query data](/azu/how-to-guides/query-data.md) · [Handle transactions](/azu/how-to-guides/handle-transactions.md)          |
| Caching and jobs | [Set up a memory cache](/azu/how-to-guides/setup-memory-cache.md) · [Set up a Redis cache](/azu/how-to-guides/setup-redis-cache.md) · [Run background jobs](/azu/how-to-guides/background-jobs.md)                                                                                                  |
| Testing          | [Test endpoints](/azu/how-to-guides/test-endpoints.md) · [Test WebSockets](/azu/how-to-guides/test-websockets.md)                                                                                                                                                                                   |
| Performance      | [Optimize endpoints](/azu/how-to-guides/optimize-endpoints.md) · [Optimize database queries](/azu/how-to-guides/optimize-database-queries.md) · [Monitor performance in development](/azu/how-to-guides/monitor-performance.md) · [Use the dev dashboard](/azu/how-to-guides/use-dev-dashboard.md)  |
| Deployment       | [Configure production](/azu/how-to-guides/configure-production.md) · [Deploy with Docker](/azu/how-to-guides/deploy-with-docker.md) · [Scale horizontally](/azu/how-to-guides/scale-horizontally.md) · [Shut down gracefully](/azu/how-to-guides/graceful-shutdown.md)                              |
| Upgrading        | [Migrate to 0.6](/azu/start-here/migrate-to-0.6.md): from the global `configure` style to `Azu::App`                                                                                                                                                                                                |

### Reference

| Area             | Pages                                                                                                                                                                                                                                                                                                                                                                                                            |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Core API         | [App](/azu/reference/app.md) · [Router](/azu/reference/router.md) · [Handler pipeline](/azu/reference/handler-pipeline.md) · [Session adapter](/azu/reference/session-adapter.md) · [Endpoint](/azu/reference/endpoint.md) · [Request](/azu/reference/request.md) · [Response](/azu/reference/response.md)                                                                                                       |
| HTTP             | [Content negotiation](/azu/reference/content-negotiation.md) · [Streaming and SSE](/azu/reference/streaming.md) · [OpenAPI](/azu/reference/openapi.md) · [Built-in handlers](/azu/reference/built-in.md) · [Error types](/azu/reference/error-types.md)                                                                                                                                                          |
| Real-time        | [Channel](/azu/reference/channel.md) · [PubSub](/azu/reference/pubsub.md) · [Presence](/azu/reference/presence.md) · [Component](/azu/reference/component.md) · [Spark client and reconnects](/azu/reference/spark-client.md) · [Spark benchmarks](/azu/reference/spark-benchmarks.md)                                                                                                                           |
| Configuration    | [Configuration options](/azu/reference/options.md) · [Spark configuration](/azu/reference/spark.md) · [Environments](/azu/reference/environments.md) · [`Azu::Env`](/azu/reference/env.md)                                                                                                                                                                                                                       |
| Templates        | [Templates and Renderable](/azu/reference/renderable.md) · [Template engine](/azu/reference/engine.md) · [Template helpers](/azu/reference/helpers.md)                                                                                                                                                                                                                                                           |
| Data and caching | [Cache](/azu/reference/cache.md) · [Redis](/azu/reference/redis.md) · [Instrumentation](/azu/reference/instrumentation.md) · [Clock](/azu/reference/clock.md) · [CQL bridge](/azu/reference/cql-bridge.md) · [Database dashboard](/azu/reference/database-dashboard.md) · [CQL API](/azu/reference/cql-api.md) · [Query methods](/azu/reference/query-methods.md) · [Validations](/azu/reference/validations.md) |
| Testing          | [Testing](/azu/reference/testing.md)                                                                                                                                                                                                                                                                                                                                                                             |
| Development      | [Dev tools](/azu/reference/azu-dev.md) (`azu/dev`) · [Database dashboard](/azu/reference/database-dashboard.md)                                                                                                                                                                                                                                                                                                  |
| Releases         | [Breaking changes](/azu/reference/breaking-changes.md): what changed in each version and how to adapt                                                                                                                                                                                                                                                                                                            |

### Concepts

| Topic           | Pages                                                                                                                                                                                                                                                                                     |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The whole box   | [Everything in the box](/azu/start-here/features.md)                                                                                                                                                                                                                                      |
| Architecture    | [Architecture overview](/azu/concepts/overview.md) · [Apps, configuration and scope](/azu/concepts/apps-and-scope.md) · [Request lifecycle](/azu/concepts/request-lifecycle.md) · [Type safety](/azu/concepts/type-safety.md) · [Performance design](/azu/concepts/performance-design.md) |
| Building blocks | [Endpoints](/azu/concepts/endpoints.md) · [Contracts](/azu/concepts/contracts.md) · [Middleware](/azu/concepts/middleware.md) · [Real-time](/azu/concepts/real-time.md) · [Components](/azu/concepts/components.md) · [Spark live views](/azu/concepts/spark-live-views.md)               |

### Contributing

* [Development setup](/azu/contributing/setup.md) · [Code standards](/azu/contributing/standards.md) · [Documentation style](/azu/contributing/docs-style.md) · [Roadmap](/azu/contributing/roadmap.md)
* [Benchmarks](https://github.com/azutoolkit/azu/blob/master/benchmark/README.md): how Azu is measured against other frameworks.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://azutopia.gitbook.io/azu/readme.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
