Executive summary
WebAssembly (Wasm) is transforming serverless computing by enabling ultra-low latency functions, eliminating the traditional "cold start" delays seen with containers and microVMs.
The CNCF project Spin offers a developer-friendly framework and command-line interface (CLI) for building Wasm applications in multiple languages and supporting rapid instantiation, strong security, and small binary sizes.
Akamai Functions provides a fully managed, globally distributed platform optimized for running Spin-based Wasm serverless functions with best-in-class performance.
This blog post demonstrates building a URL shortener using Rust, Spin, and Akamai Functions, highlighting a streamlined workflow from local development and testing to global deployment.
By using Wasm and Spin, developers can deploy high-performance, event-driven serverless workloads at the edge, achieving near-instant startup and minimal latency worldwide.
If you’ve been following the Wasm space, you’ve likely seen the format used to bring heavy-duty C++ libraries to the browser or to make apps such as Figma run like a native app. Lately, however, Wasm has been moving upstream, away from the client and into the cloud.
If you’re a developer used to traditional serverless runtimes, you’re familiar with the cold start tax. You sacrifice those first few hundred milliseconds of execution time while a container or a microVM warms up, gets your workload assigned, and starts instantiating it.
In this blog post, we’re going to look at how you can use the Cloud Native Computing Foundation (CNCF) project Spin — the developer tool for building Wasm applications — to create serverless functions that start in less than 0.5 milliseconds. We’ll go from a blank directory to a globally distributed URL shortener that runs on top of Akamai Functions.
4 reasons to use Wasm for serverless functions
Before we dive into the code, let’s talk about the four reasons to use Wasm instead of other, more traditional technologies (like containers) for your serverless functions.
Instant instantiation. Wasm modules are tiny and have a predictable memory footprint. This allows the host to "spin" them up in sub-millisecond time.
Near-native runtime performance. Wasm aims to execute at native speed by taking advantage of common hardware capabilities to accelerate your compute-intense workloads.
Security sandbox. By default, a Wasm module is "locked in." It can't see the underlying filesystem, talk to the network, or access environment variables unless you explicitly grant those capabilities to your application.
Tiny binaries. A "hello world" HTTP function, written in Rust and created with Spin, is approximately 280 KB.
What is Spin?
Spin is an open source framework and CLI designed to streamline the process of building and running Wasm applications on the server.
Spin provides a best-in-class developer experience for building Wasm applications whether you're using Rust, Python, Go, JavaScript, or TypeScript.
You should definitely use the language-specific SDKs provided by Spin to boost your developer productivity while addressing common requirements like talking to third-party services or querying a database.
At the beginning of 2025, Spin joined the CNCF as a project on the Sandbox tier.
What is Akamai Functions?
Akamai Functions is a fully managed, multi-tenant serverless platform on which you can run your Spin applications.
The service distributes your Spin apps to all service regions across the globe without needing any additional configuration. Built on top of Akamai Cloud, it provides best-in-class runtime performance and ultra-low latency.
Get started by installing the Spin CLI
To follow along, you’ll need to install the Spin CLI. If you haven't done that yet, you can grab it with a single command:
# For macOS/Linux/WSL
curl -fsSL https://spinframework.dev/downloads/install.sh | bash
Note: Consult the Spin documentation to find detailed installation instructions and guides on how to install Spin CLI, also using Homebrew.
On top of the Spin CLI, you'll also need a language toolchain (we'll use Rust for the sake of this article, but Spin supports TypeScript, Go, Python, and others as well).
To install Rust on your system, you can follow the Rust installation instructions. Once you've installed Rust, you have to add the wasm32-wasip1 target. Run rustup target add wasm32-wasip1 to install it.
The 6 steps to build and run serverless functions with Spin
There are six steps to build serverless functions with Spin and run them with ultra-low latency on top of Akamai Functions.
Create a new project
Configure the key-value store
Implement the logic
Compiling to WebAssembly
Local testing
Deploying to Akamai Functions
Step 1: Create a new project
Let's start by scaffolding a new project. We'll use the Rust HTTP template (http-rust) to build a simple URL shortener:
spin new -t http-rust --accept-defaults url-shortener
cd url-shortener
Every Spin application consists of a source project that follows common idioms based on the chosen programming language (meaning that our Spin Rust application looks like any other Rust application). Additionally, you'll find the application manifest (spin.toml) being scaffolded in the root of the project directory. You use the application manifest to:
Specify application metadata
Configure application components and their triggers
Grant application components capabilities (e.g., by using the built-in key-value store)
Step 2: Configure the key-value store
Our URL shortener needs a place to store links. Spin provides a built-in key-value store that works locally and in the cloud without the need to manage any additional service or configure cloud infrastructure. It just works.
First, we need to tell Spin that our component is allowed to access this store. Open spin.toml and add the key_value_stores line:
[component.url-shortener]
source = "target/wasm32-wasip1/release/url_shortener.wasm"
allowed_outbound_hosts = []
key_value_stores = ["default"] # Grant access to the default KV store
[component.url-shortener.build]
command = "cargo build --target wasm32-wasip1 --release"
Step 3: Implement the logic
Now, let's look at the code. We want to do two things:
Save a URL: Take a short code and a destination URL and save them to the key-value store.
Redirect: Take a short code from the URL path, look it up, and return an HTTP 301.
Because we want to receive new links as JSON, we will use serde and serde_json; two popular crates (i.e., libraries) from the Rust ecosystem to streamline serialization and deserialization into regular Rust data structures.
To add those as dependencies, we’ll use cargo (which comes with your Rust installation):
# Add serde including the derive feature
cargo add serde -F derive
# Add serde_json
cargo add serde_json
The Spin Rust SDK provides all the APIs we need to address our requirements. We'll use the Router provided by the http module to layout the endpoints of our application and to handle incoming requests.
Also, we'll use the Store structure provided by the key_value module to interact with the key-value store. A simple LinkModel structure is used to define the API contract:
use anyhow::Result;
use serde::{Deserialize, Serialize};
use spin_sdk::http::{IntoResponse, Params, Request, Response, ResponseBuilder, Router};
use spin_sdk::http_component;
use spin_sdk::key_value::Store;
#[http_component]
fn handle_hello_wasm_functions(req: Request) -> Result<impl IntoResponse> {
let mut router = Router::default();
router.get("/:short", try_follow_link);
router.post("/_api/links", add_link);
Ok(router.handle(req))
}
fn add_link(req: Request, _params: Params) -> Result<impl IntoResponse> {
let Ok(model) = serde_json::from_slice::<LinkModel>(req.body()) else {
return Ok(Response::new(400, "Bad Request"));
};
let store = Store::open_default()?;
store.set_json(model.short.clone(), &model)?;
Ok(Response::new(201, ()))
}
fn try_follow_link(_req: Request, params: Params) -> Result<impl IntoResponse> {
let Some(short) = params.get("short") else {
return Ok(Response::new(400, "Bad Request"));
};
let store = Store::open_default()?;
Ok(match store.get_json::<LinkModel>(short)? {
Some(model) => ResponseBuilder::new(301)
.header("Location", model.url)
.body(())
.build(),
None => Response::new(404, "Not Found"),
})
}
#[derive(Deserialize, Serialize)]
pub struct LinkModel {
short: String,
url: String,
}
Just a few lines of code: That's all we need to implement for building a super simple URL shortener that leverages the built-in key-value store for persistence.
Step 4: Compiling to WebAssembly
Thanks to Spin, we don't have to worry very much about how each particular language wants their code to be turned into Wasm. Spin provides the language-agnostic spin build command, which takes care of invoking language-specific commands to compile our source down to Wasm.
Note: Take a look at the application manifest (spin.toml). You can find language-specific build instructions per component. This allows further customization and optimization to integrate seamlessly with existing tools, and services to meet all requirements of your development lifecycle.
Run spin build from within the application directory:
spin build
Building component url-shortener with `cargo build --target wasm32-wasip1 --release`
# snip
Compiling url-shortener v0.1.0 (~/demos/url-shortener)
Finished `release` profile [optimized] target(s) in 5.16s
Finished building all Spin components
Step 5: Local testing
One of the best parts of the Spin developer experience is the local runtime. When you invoke spin up, it starts a local server and even simulates the key-value store (by creating a local SQLite database for you):
spin up
Logging component stdio to ".spin/logs/"
Storing default key-value data to ".spin/sqlite_key_value.db".
Serving http://127.0.0.1:3000
Available Routes:
url-shortener: http://127.0.0.1:3000 (wildcard)
You can now test your serverless function locally at http://localhost:3000:
# Check for a non-existing link
curl -i localhost:3000/web
HTTP/1.1 404 Not Found
transfer-encoding: chunked
date: Wed, 04 Feb 2026 15:56:34 GMT
Not Found
# Add a new Link
# --json requires curl >= 7.82,0
curl -i --json '{"short": "web", "url": "https://akamai.com"}' localhost:3000/_api/links
HTTP/1.1 201 Created
transfer-encoding: chunked
date: Wed, 04 Feb 2026 16:00:43 GMT
# Check for an existing link
curl -i localhost:3000/web
HTTP/1.1 301 Moved Permanently
location: https://akamai.com
transfer-encoding: chunked
date: Wed, 04 Feb 2026 16:01:40 GMT
No heavy Docker containers or local Kubernetes clusters are required.
Step 6: Deploying to Akamai Functions
Once you're happy with the local results, it’s time to go live. Because Wasm is architecture-agnostic, the binary you just built locally is the exact same one that will run in production.
To deploy a Spin application to Akamai Functions, you must have an Akamai Functions account and your local installation of spin must be authorized for interacting with the service on your behalf. (You can use this form to request access to Akamai Functions.)
To authorize your installation of spin, use the spin aka login command and follow the instructions shown in your terminal.
Once authorized, deploying is as easy as running spin aka deploy:
spin aka deploy
Name of new app: url-shortener
Creating new app url-shortener in account thorstenhans
Note: If you would instead like to deploy to an existing app, cancel this deploy and link this workspace to the app with spin aka app link
OK to continue? yes
Workspace linked to app url-shortener
Waiting for app to be ready... ready
App Routes:
- url-shortener: https://40a7af2f-9c43-4b35-ac74-c40ce89f4430.fwf.app (wildcard)
Note: Spin applications are distributed as OCI artifacts. Our URL shortener consists of just two tiny layers:
The application manifest (spin.toml)
The application binary (.wasm)
Deploying a Spin application to Akamai Functions takes approximately 45 seconds. As part of the deployment, your application will be distributed to all service regions across the globe. Also, a generic subdomain is registered and assigned to your application. Akamai Functions routes incoming requests to the closest service region to provide the lowest possible latency, no matter where inbound requests originate.
The spin aka deploy command will print the public endpoint of your Spin application to the terminal. You can use curl to verify that our application works as expected and responds within milliseconds:
# Check for a non-existing link
curl -i https://40a7af2f-9c43-4b35-ac74-c40ce89f4430.fwf.app/web
HTTP/1.1 404 Not Found
x-envoy-upstream-service-time: 11
Server: envoy
Date: Wed, 04 Feb 2026 16:06:45 GMT
Content-Length: 9
Connection: keep-alive
Akamai-Request-BC: [a=184.25.51.68,b=82806798,c=g,n=DE_HE_FRANKFURT,o=20940],[a=230,c=o]
Set-Cookie: akaalb_fwf-prod-apps=~op=fwf_prod:fwf-dev-de-fra-2|~rv=91~m=fwf-dev-de-fra-2:0|~os=1231e1ede8704e97468b2ddc2c84cd5b~id=fbdb58837eb19292c249c7f80e319e1a; path=/; HttpOnly; Secure; SameSite=None
Akamai-GRN: 0.443319b8.1770221205.4ef880e
Not Found
# Add a new Link
# --json requires curl >= 7.82,0
curl -i --json '{"short": "web", "url": "https://akamai.com"}' https://40a7af2f-9c43-4b35-ac74-c40ce89f4430.fwf.app/_api/links
HTTP/1.1 201 Created
x-envoy-upstream-service-time: 13
Server: envoy
Date: Wed, 04 Feb 2026 16:07:05 GMT
Connection: close
Akamai-Request-BC: [a=184.25.51.62,b=190644756,c=g,n=DE_HE_FRANKFURT,o=20940],[a=230,c=o]
Set-Cookie: akaalb_fwf-prod-apps=~op=fwf_prod:fwf-dev-de-fra-2|~rv=89~m=fwf-dev-de-fra-2:0|~os=1231e1ede8704e97468b2ddc2c84cd5b~id=4649e92b3073fe68c6f680c9f8ceaeca; path=/; HttpOnly; Secure; SameSite=None
Akamai-GRN: 0.3e3319b8.1770221225.b5d0214
# Check for an existing link
curl -i https://40a7af2f-9c43-4b35-ac74-c40ce89f4430.fwf.app/web
HTTP/1.1 301 Moved Permanently
Location: https://akamai.com
x-envoy-upstream-service-time: 12
Server: envoy
Date: Wed, 04 Feb 2026 16:07:22 GMT
Connection: close
Akamai-Request-BC: [a=184.25.51.68,b=82872680,c=g,n=DE_HE_FRANKFURT,o=20940],[a=230,c=o]
Set-Cookie: akaalb_fwf-prod-apps=~op=fwf_prod:fwf-dev-de-fra-2|~rv=53~m=fwf-dev-de-fra-2:0|~os=1231e1ede8704e97468b2ddc2c84cd5b~id=e675b7ee135c00fdce6d55d268a73be8; path=/; HttpOnly; Secure; SameSite=None
Akamai-GRN: 0.443319b8.1770221242.4f08968
Companion video and repository
Want a detailed walk-through? Watch this companion video.
Serverless Functions with Zero Cold Starts: WebAssembly + Spin
All code is also available on GitHub.
Conclusion
Wasm in the cloud isn't about replacing everything we know — it's about adding a new tool to our portfolio for high-performance, event-driven workloads. By moving logic to Wasm and the edge, we eliminate the latency that has plagued serverless functions for years.
Join our community
If you’re interested in digging deeper and connecting with fellow developers, we're more than happy to welcome you to our community on Discord, where we hang out, assist one another, and talk about what's new and important to us as developers.
Tags