Virke Components
Virke supports the WebAssembly Component Model, a portable binary interface standard for WebAssembly. Component Model applications are more portable, composable, and future-proof than traditional Wasm modules.
Quick Start
1. Create a component project
virke init --name my-component --type component
bun add @virke/wasm-component
2. Write your handler
import { defineHandler, json, kv, db, logging } from "@virke/wasm-component";
export default defineHandler(async (request) => {
logging.log("info", `${request.method} ${request.url}`);
const counter = kv.get("counter") ?? "0";
kv.set("counter", String(Number.parseInt(counter) + 1), 3600);
return json({ visits: Number.parseInt(counter) + 1 });
});
3. Deploy
virke deploy
The CLI detects type = "component" in virke.toml and uses the Component Model build pipeline: bundle with Bun, componentize with componentize-js, upload the .wasm component.
How It Works
Your TypeScript code
↓ (bun build)
Bundled JavaScript
↓ (componentize-js)
Wasm Component (.wasm)
↓ (virke deploy)
Fastly Compute@Edge service
Your component exports a wasi:http/incoming-handler and imports Virke runtime interfaces for KV, DB, OS3, and logging. The Virke runtime on Fastly Compute@Edge provides host implementations of these interfaces.
Virke Bindings
KV Store
import { kv } from "@virke/wasm-component";
// Read
const value = kv.get("my-key"); // string | undefined
// Write with TTL (seconds)
kv.set("my-key", "my-value", 3600);
// Delete
kv.delete("my-key");
// List keys by prefix
const keys = kv.list("user:", 100);
Database
import { db } from "@virke/wasm-component";
// Read query
const result = db.query("SELECT * FROM users WHERE id = ?", ["123"]);
// Write
const affected = db.execute(
"INSERT INTO users (name, email) VALUES (?, ?)",
["Alice", "alice@example.com"]
);
Object Storage
import { os3 } from "@virke/wasm-component";
// Read
const data = os3.get("documents/file.pdf"); // Uint8Array
// Write
os3.put("documents/file.pdf", data, "application/pdf");
// Delete
os3.delete("documents/file.pdf");
// List
const keys = os3.list("documents/", 100);
Logging
import { logging } from "@virke/wasm-component";
logging.log("debug", "Debug message");
logging.log("info", "Request processed");
logging.log("warn", "Rate limit approaching");
logging.log("error", "Database query failed");
Configuration
virke.toml
[project]
name = "my-component-app"
type = "component"
[compute]
entry = "src/handler.ts"
package.json
{
"dependencies": {
"@virke/wasm-component": "^0.0.1"
}
}
WIT Interface Definitions
Virke defines its runtime interfaces using WIT (Wasm Interface Type):
world virke {
import kv;
import db;
import os3;
import logging;
export wasi:http/incoming-handler@0.2.0;
}
Full WIT definitions
interface kv {
get: func(key: string) -> option<string>;
set: func(key: string, value: string, ttl: option<u32>) -> result<_, string>;
delete: func(key: string) -> result<_, string>;
list: func(prefix: string, limit: option<u32>) -> list<string>;
}
interface db {
type query-result = string;
query: func(sql: string, params: list<string>) -> result<query-result, string>;
execute: func(sql: string, params: list<string>) -> result<u64, string>;
}
interface os3 {
get: func(key: string) -> result<list<u8>, string>;
put: func(key: string, data: list<u8>, content-type: option<string>) -> result<_, string>;
delete: func(key: string) -> result<_, string>;
list: func(prefix: string, limit: option<u32>) -> list<string>;
}
interface logging {
enum level { debug, info, warn, error }
log: func(level: level, message: string);
}
Performance
| Metric | Value |
|---|---|
| Component size | 500 KB – 2 MB |
| Cold start | 60–110ms |
| KV operations | 30–50ms |
| DB queries (cached) | 10–50ms |
| DB writes | 1–2s |
| OS3 operations | 50–200ms |
| Logging | < 1ms |
Component Model vs Traditional Compute
| Component Model | Traditional (Virke Run) | |
|---|---|---|
| Interface | WIT-defined imports/exports | Fastly SDK directly |
| Portability | Any Component Model runtime | Fastly only |
| Composability | Clean import/export interfaces | N/A |
| Languages | TypeScript (more coming) | TypeScript, Rust |
| Bundle size | Larger (includes JS runtime) | Smaller |
| Maturity | Newer | Stable |
Choose Component Model when portability and composability matter. Choose Virke Run for the most mature developer experience and smallest bundle sizes.
Security
Components run in a capability-based sandbox:
- No ambient authority — components can only access explicitly imported capabilities
- Wasm sandboxing — memory isolation via wasmtime
- No direct filesystem — all storage goes through host-provided interfaces
- No raw network access — only via host-provided HTTP handler
Limitations
- TypeScript only (Rust and other languages via
wit-bindgencoming in V2.1) - Larger bundle size than native Rust (includes StarlingMonkey JS runtime)
- Component Model tooling is still maturing
- No streaming — full request/response bodies (streaming planned for V2.1)
Further Reading
- Virke Run — Traditional compute with Virke Run
- Configuration —
virke.tomlreference for component projects - Virke DB — Database access from components
- Virke KV — KV access from components