| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
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:
- a program like
watchexecthat runs your axum server Rust code and when it detects changes in the filesystem, restarts such server - your axum server Rust code with your main logic and also an endpoint to send an event to the browser when it will restart
- the browser page, which listens to the server-sent events and reloads the page on demand
How to use it:
- install
watchexec - run
watchexec --socket 8080 --restart --stop-signal SIGINT -- cargo run - open your browser in http://localhost:8080
- 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.