Back to templates

Template details

Rust waitUntil

Run background work after the response is sent using waitUntil in the Vercel Rust runtime.

About this template

Rust waitUntil is a Vercel starter template that demonstrates scheduling background work after the HTTP response is sent, using the waitUntil API in the Vercel Rust runtime (vercel_runtime 2.4.0+). It takes incoming requests to /api/wait-until, captures request metadata, writes it to Upstash Redis in the background, and returns the response immediately so the client never waits for the side effect.

What is Rust waitUntil?

Rust waitUntil is a reference implementation published by Vercel that shows how to use the waitUntil function in Rust serverless functions. It receives HTTP requests, extracts timestamp, method, user agent, and the visitor's country from the x-vercel-ip-country edge header, then schedules a Redis write via AppState::wait_until. The output is a JSON response to the client and a record stored in Upstash Redis containing the last 10 requests. It runs on Vercel's Rust runtime and is part of the official Vercel examples repository.

Key Features

  • waitUntil API support — registers a future via AppState::wait_until that is spawned immediately, decoupled from the response, and drained at process shutdown with a 30-second timeout.
  • Upstash Redis integration — uses the REST /pipeline endpoint to run LPUSH and LTRIM key 0 9, keeping only the 10 most recent records.
  • Read-only token separation — writes use KV_REST_API_TOKEN and reads use KV_REST_API_READ_ONLY_TOKEN, so read endpoints don't have write access.
  • Geolocation from header — reads x-vercel-ip-country (ISO 3166-1 alpha-2) to display a flag emoji, without storing the visitor's IP.
  • Front-end demo — a single index.html fires a request and renders the last 10 records from /api/recent.
  • Rust project structure — includes api/wait-until.rs, api/recent.rs, Cargo.toml, and vercel.json for deployment configuration.

Who is it for?

Rust developers deploying to Vercel who want to offload non-critical work from the request path. Backend engineers learning how waitUntil behaves in the Rust runtime compared to Node.js. Teams using Upstash Redis (Vercel KV) who need a minimal example of background writes with read-only access for separate endpoints.

What can you do with Rust waitUntil?

  • Analytics tracking: Record API requests to Redis after the response is sent, eliminating client wait time.
  • Cache warming: Trigger cache refreshes as a background task after a request completes.
  • Webhook delivery: Send outbound webhooks without delaying the main response.
  • Database logging: Write request logs to a datastore with minimal latency impact.

How does it work?

The handler in api/wait-until.rs builds a JSON record with timestamp, method, user agent, and country, then calls state.wait_until with an async closure that writes the record to Upstash. The runtime spawns the future immediately, returns the response to the client, and drains any pending work at shutdown within a 30-second budget. A separate endpoint /api/recent reads back the last 10 records using LRANGE.

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 example intentionally uses println!/eprintln! for logging from background tasks because log_context attaches to the request invocation, which closes when the response is sent. stdout/stderr are captured independently of request context, ensuring background logs appear in function logs.

FAQ

What version of vercel_runtime is required?

The template requires vercel_runtime version 2.4.0 or higher for waitUntil support.

Does waitUntil delay the response?

No. The background task is decoupled from the response — the handler returns immediately and the client receives the response without waiting for the Redis write to finish.

What happens if a background task panics?

The panic is isolated and does not affect the response or other background work. Tasks are drained at process shutdown within a 30-second timeout.

Why does the template use stdout/stderr for logging from background work?

Because log_context is tied to the current request invocation, which closes when the response is sent. println! and eprintln! are captured independently of request context, so they reliably appear in function logs.

How do I run this locally?

Clone the Vercel examples repository, install Rust, run vercel env pull .env.local to fetch your environment variables, then start with vc dev and open the printed URL.

screenshot of Rust waitUntil on template0.com