No description
Find a file
2026-03-04 10:03:58 +01:00
src First commit 2026-02-14 11:39:04 +01:00
.gitignore First commit 2026-02-14 11:39:04 +01:00
Cargo.lock First commit 2026-02-14 11:39:04 +01:00
Cargo.toml First commit 2026-02-14 11:39:04 +01:00
README.md Add link back to blog 2026-03-04 10:03:58 +01:00

Axum web auto-reload example

This repo is an example using axum 0.8 to implement a server auto-reload mechanism, that refreshes your open browser pages when some source file changes in your repo.

It has three main pieces:

  1. a program like watchexec that runs your axum server Rust code and when it detects changes in the filesystem, restarts such server
  2. your axum server Rust code with your main logic and also an endpoint to send an event to the browser when it will restart
  3. the browser page, which listens to the server-sent events and reloads the page on demand

How to use it:

  1. install watchexec
  2. run watchexec --socket 8080 --restart --stop-signal SIGINT -- cargo run
  3. open your browser in http://localhost:8080
  4. modify some source file and watch the browser reload

Check this blog post where I go into more details of this design: https://sitegui.dev/post/2026/web-server-auto-reload-in-rust.

Basic restart flow

The basic overview of the restart flow is:

sequenceDiagram
    autonumber
    watchexec ->> your server: spawn
    browser ->> your server: request page
    browser ->> your server: connect to /auto_refresh
    watchexec ->> watchexec: detect file change
    watchexec ->> your server: interrupt
    destroy your server
    your server -->> browser: send message
    browser ->> browser: reload
    create participant your new server
    watchexec ->> your new server: spawn

Smooth reload with socket activation

The diagram above will not work in practice if your new server does not start fast enough, because when the browser reloads, it will try to request your page, and it will fail to connect to the port, since the previous server is down and the new one hasn't yet listened to the target port.

To solve this, we can ask the watchexec process to listen to the port and "borrow" this socket down to our spawned server. This is what the --socket flag does.

This way, the connection flow goes like this:

sequenceDiagram
    autonumber
    watchexec ->> socket: listen to port
    watchexec ->> your server: spawn and pass socket
    your server ->> socket: accept
    browser ->> socket: connect
    socket -->> your server: new connection
    destroy your server
    watchexec ->> your server: interrupt
    browser ->> socket: connect
    create participant your new server
    watchexec ->> your new server: spawn and pass socket
    your new server ->> socket: accept
    socket -->> your new server: new connection

Note how the socket is created by watchexec, but the new connections are accepted by your axum server. This way, when the browser reloads, it can send the connection request to the open socket and wait for the new server to accept and answer it back.

The Rust code uses the crate listenfd to get the passed socket.