
Rust waitUntil
This example demonstrates waitUntil support in the Vercel Rust runtime
(vercel_runtime 2.4.0+). waitUntil lets you schedule background work that
keeps running after the HTTP response has already been sent to the client —
the Rust analog of waitUntil
in the Node.js runtime.
This is ideal for fire-and-forget side effects the client shouldn't have to wait for, such as flushing analytics, warming a cache, sending a webhook, or writing to a database.
Here, every request to /api/wait-until records itself — timestamp, method,
user agent, and the visitor's country (with a flag emoji) — into
Upstash Redis after the response is sent. The
front-end then reads the last 10 records from /api/recent.
The country comes from Vercel's x-vercel-ip-country request header (an ISO
3166-1 alpha-2 code injected at the edge), which is converted to a flag emoji
in country_to_flag. The IP itself is never stored.
How it works
api/wait-until.rs defines a handler that receives the runtime's AppState.
AppState::wait_until registers a future that is:
- Spawned immediately, so it makes progress between requests.
- Decoupled from the response — the handler returns right away and the client gets its response without waiting for the background task.
- Drained at process shutdown (bounded by a 30s timeout), matching the Node.js runtime's behavior. A panic in the background task is isolated and never affects the response or other background work.
// Capture request details before moving into the background task.let record = json!({ "timestamp": ts, "method": method, "userAgent": ua, "country": country, "flag": flag });state.wait_until(async move {// Runs after the response has been sent. The client never waits for this.if let Err(e) = store_request(&record).await {eprintln!("[waitUntil] Failed to store request record: {e}");}});
The write uses the Upstash REST /pipeline endpoint to run LPUSH followed by
LTRIM key 0 9, keeping only the 10 most recent records (newest first).
api/recent.rs reads them back with LRANGE key 0 9 using the read-only
token and returns them as JSON for the front-end to render.
Data flow
GET /api/wait-until→ responds immediately, schedules the Redis write viawaitUntil.- Background task →
LPUSH+LTRIMto Upstash (write token). GET /api/recent→LRANGEthe last 10 records (read-only token).index.html→ "Fire a request", then renders the recent list.
Logging from background work
The example logs from the background task with println!/eprintln!
(stdout/stderr) rather than the request-scoped state.log_context. This is
intentional:
log_contextattaches each line to the current invocation's id.- The runtime sends the per-request
endmessage as soon as the handler returns the response, which closes that invocation's log stream. waitUntilwork is drained later (at process shutdown, bounded by a 30s timeout). By then the originating request context is closed, so alog_contextline emitted from the background task would not be attributed to the request and may be dropped.
stdout/stderr is captured independently of request context, so it reliably shows
up in the function logs — making the background work observable. Use
log_context for synchronous, in-handler logging and println!/eprintln!
(or an external sink like a database/Blob) for waitUntil work.
Project Structure
api/wait-until.rs— records the request to Upstash in the background viawaitUntilapi/recent.rs— reads the last 10 records back with the read-only tokenindex.html— fires requests and renders the recent listCargo.toml— Rust dependencies and binary configurationvercel.json— Vercel project configuration
Environment variables
This example uses an Upstash Redis (Vercel KV) database. Add the integration from the Vercel dashboard, or set these variables on your project:
| Variable | Used by | Purpose |
|---|---|---|
KV_REST_API_URL | both endpoints | Upstash REST base URL |
KV_REST_API_TOKEN | /api/wait-until | Read/write token (writes records) |
KV_REST_API_READ_ONLY_TOKEN | /api/recent | Read-only token (reads records) |
For local development, copy these into a .env.local file (gitignored).
Development
Clone the repository:
git clone https://github.com/vercel/examples.gitcd examples/rust/wait-until
Install Rust if you haven't already:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Pull your project's environment variables (or create .env.local manually):
vercel env pull .env.local
Test locally:
vc dev
Open the printed URL, click Fire a request, and watch the recent list update. The response returns instantly while the record is written to Upstash in the background.


