> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/tokio-rs/axum/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Build your first HTTP server with Axum in minutes

This guide will walk you through creating a simple HTTP server with Axum. You'll learn the basics of routing, handlers, and serving your application.

## Hello, World!

Let's start with the simplest possible Axum application.

<Steps>
  <Step title="Create the project">
    If you haven't already, create a new Rust project and add dependencies:

    ```bash theme={null}
    cargo new hello-axum
    cd hello-axum
    ```

    Update `Cargo.toml`:

    ```toml theme={null}
    [dependencies]
    axum = "0.8.8"
    tokio = { version = "1.0", features = ["full"] }
    ```
  </Step>

  <Step title="Write the server code">
    Replace the contents of `src/main.rs` with this code:

    ```rust theme={null}
    use axum::{response::Html, routing::get, Router};

    #[tokio::main]
    async fn main() {
        // Build our application with a route
        let app = Router::new().route("/", get(handler));

        // Run it
        let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
            .await
            .unwrap();
        println!("listening on {}", listener.local_addr().unwrap());
        axum::serve(listener, app).await;
    }

    async fn handler() -> Html<&'static str> {
        Html("<h1>Hello, World!</h1>")
    }
    ```
  </Step>

  <Step title="Run the server">
    Start your server:

    ```bash theme={null}
    cargo run
    ```

    You should see:

    ```
    listening on 127.0.0.1:3000
    ```
  </Step>

  <Step title="Test the endpoint">
    Open your browser to [http://localhost:3000](http://localhost:3000) or use curl:

    ```bash theme={null}
    curl http://localhost:3000
    ```

    You should see:

    ```html theme={null}
    <h1>Hello, World!</h1>
    ```
  </Step>
</Steps>

<Note>
  The `#[tokio::main]` macro sets up the async runtime. All Axum handlers are async functions.
</Note>

## Understanding the code

Let's break down what's happening:

### Router

```rust theme={null}
let app = Router::new().route("/", get(handler));
```

The `Router` is the core of your application. You add routes using the `.route()` method, specifying:

* The path (`"/"`)
* The HTTP method (`get`)
* The handler function (`handler`)

### Handler

```rust theme={null}
async fn handler() -> Html<&'static str> {
    Html("<h1>Hello, World!</h1>")
}
```

Handlers are async functions that return something that implements `IntoResponse`. The `Html` type tells Axum to set the `Content-Type` header to `text/html`.

### Server

```rust theme={null}
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
    .await
    .unwrap();
axum::serve(listener, app).await;
```

This creates a TCP listener and serves your application on port 3000.

## Multiple routes

Let's add more routes to handle different paths and HTTP methods:

```rust theme={null}
use axum::{routing::{get, post}, http::StatusCode, Json, Router};
use serde::{Deserialize, Serialize};

#[tokio::main]
async fn main() {
    // Initialize tracing
    tracing_subscriber::fmt::init();

    // Build our application with multiple routes
    let app = Router::new()
        .route("/", get(root))
        .route("/users", post(create_user));

    // Run it
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    tracing::debug!("listening on {}", listener.local_addr().unwrap());
    axum::serve(listener, app).await;
}

// Basic handler that responds with a static string
async fn root() -> &'static str {
    "Hello, World!"
}

async fn create_user(
    // This argument tells axum to parse the request body
    // as JSON into a `CreateUser` type
    Json(payload): Json<CreateUser>,
) -> (StatusCode, Json<User>) {
    // Insert your application logic here
    let user = User {
        id: 1337,
        username: payload.username,
    };

    // This will be converted into a JSON response
    // with a status code of `201 Created`
    (StatusCode::CREATED, Json(user))
}

// The input to our `create_user` handler
#[derive(Deserialize)]
struct CreateUser {
    username: String,
}

// The output to our `create_user` handler
#[derive(Serialize)]
struct User {
    id: u64,
    username: String,
}
```

<Tip>
  Add `serde = { version = "1.0", features = ["derive"] }` and `tracing-subscriber = "0.3"` to your dependencies to run this example.
</Tip>

## Testing the JSON endpoint

Test the POST endpoint with curl:

```bash theme={null}
curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{"username": "alice"}'
```

Response:

```json theme={null}
{
  "id": 1337,
  "username": "alice"
}
```

## Working with extractors

Axum provides extractors to parse different parts of requests:

<CodeGroup>
  ```rust JSON body theme={null}
  use axum::Json;
  use serde::Deserialize;

  #[derive(Deserialize)]
  struct Input {
      name: String,
  }

  async fn handler(Json(payload): Json<Input>) -> String {
      format!("Hello, {}!", payload.name)
  }
  ```

  ```rust Path parameters theme={null}
  use axum::extract::Path;

  async fn user_profile(Path(user_id): Path<u64>) -> String {
      format!("Profile for user {}", user_id)
  }

  // Route: .route("/users/:id", get(user_profile))
  ```

  ```rust Query parameters theme={null}
  use axum::extract::Query;
  use serde::Deserialize;

  #[derive(Deserialize)]
  struct Pagination {
      page: usize,
      per_page: usize,
  }

  async fn list_users(Query(pagination): Query<Pagination>) -> String {
      format!("Page {} with {} items", pagination.page, pagination.per_page)
  }

  // Example: GET /users?page=1&per_page=10
  ```

  ```rust Headers theme={null}
  use axum::http::HeaderMap;

  async fn handler(headers: HeaderMap) -> String {
      let user_agent = headers
          .get("user-agent")
          .and_then(|v| v.to_str().ok())
          .unwrap_or("unknown");
      format!("Your user agent: {}", user_agent)
  }
  ```
</CodeGroup>

## Response types

Handlers can return different response types:

<CodeGroup>
  ```rust Plain text theme={null}
  async fn handler() -> &'static str {
      "Hello, World!"
  }
  ```

  ```rust JSON theme={null}
  use axum::Json;
  use serde::Serialize;

  #[derive(Serialize)]
  struct Message {
      text: String,
  }

  async fn handler() -> Json<Message> {
      Json(Message {
          text: "Hello, World!".to_string(),
      })
  }
  ```

  ```rust HTML theme={null}
  use axum::response::Html;

  async fn handler() -> Html<&'static str> {
      Html("<h1>Hello, World!</h1>")
  }
  ```

  ```rust Custom status code theme={null}
  use axum::http::StatusCode;

  async fn handler() -> (StatusCode, &'static str) {
      (StatusCode::CREATED, "Resource created")
  }
  ```

  ```rust Result type theme={null}
  use axum::{http::StatusCode, Json};
  use serde::Serialize;

  #[derive(Serialize)]
  struct User {
      id: u64,
      name: String,
  }

  async fn handler() -> Result<Json<User>, StatusCode> {
      let user = fetch_user().await
          .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
      Ok(Json(user))
  }
  ```
</CodeGroup>

## Adding middleware

Use Tower middleware to add cross-cutting concerns:

```rust theme={null}
use tower_http::trace::TraceLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

#[tokio::main]
async fn main() {
    // Initialize tracing
    tracing_subscriber::registry()
        .with(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| "info".into()),
        )
        .with(tracing_subscriber::fmt::layer())
        .init();

    let app = Router::new()
        .route("/", get(handler))
        // Add middleware
        .layer(TraceLayer::new_for_http());

    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    tracing::info!("listening on {}", listener.local_addr().unwrap());
    axum::serve(listener, app).await;
}

async fn handler() -> &'static str {
    "Hello, World!"
}
```

<Info>
  Add `tower-http = { version = "0.6", features = ["trace"] }` to use `TraceLayer`.
</Info>

## What's next?

You now have a working Axum application! Here are some next steps:

<CardGroup cols={2}>
  <Card title="Routing" icon="route">
    Learn about advanced routing patterns and path parameters
  </Card>

  <Card title="Extractors" icon="filter">
    Deep dive into request extractors and validation
  </Card>

  <Card title="State management" icon="database">
    Share application state across handlers
  </Card>

  <Card title="Middleware" icon="layer-group">
    Add authentication, logging, and other cross-cutting concerns
  </Card>
</CardGroup>

## Full example

Here's the complete example from this guide:

```rust theme={null}
use axum::{
    routing::{get, post},
    http::StatusCode,
    Json, Router,
};
use serde::{Deserialize, Serialize};

#[tokio::main]
async fn main() {
    // Initialize tracing
    tracing_subscriber::fmt::init();

    // Build our application with a route
    let app = Router::new()
        // `GET /` goes to `root`
        .route("/", get(root))
        // `POST /users` goes to `create_user`
        .route("/users", post(create_user));

    // Run our app with hyper
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    tracing::debug!("listening on {}", listener.local_addr().unwrap());
    axum::serve(listener, app).await;
}

// Basic handler that responds with a static string
async fn root() -> &'static str {
    "Hello, World!"
}

async fn create_user(
    // This argument tells axum to parse the request body
    // as JSON into a `CreateUser` type
    Json(payload): Json<CreateUser>,
) -> (StatusCode, Json<User>) {
    // Insert your application logic here
    let user = User {
        id: 1337,
        username: payload.username,
    };

    // This will be converted into a JSON response
    // with a status code of `201 Created`
    (StatusCode::CREATED, Json(user))
}

// The input to our `create_user` handler
#[derive(Deserialize)]
struct CreateUser {
    username: String,
}

// The output to our `create_user` handler
#[derive(Serialize)]
struct User {
    id: u64,
    username: String,
}
```

<Tip>
  Find more complete examples in the [Axum examples directory](https://github.com/tokio-rs/axum/tree/main/examples).
</Tip>
