HTTP Server

Expose a storage instance through a Fetch-compatible handler and connect to it with the HTTP driver.

#Create a handler

createStorageHandler returns a standard (Request) => Response fetch handler. It works with servers and runtimes that accept a Fetch API handler.

The following example uses srvx:

npm i srvx
server.ts
import { serve } from "srvx";
import { createStorage } from "unstorage";
import { createStorageHandler } from "unstorage/server";
import fsDriver from "unstorage/drivers/fs";

const storage = createStorage({
  driver: fsDriver({ base: "./data" }),
});

const fetch = createStorageHandler(storage, {
  authorize({ request, key, type }) {
    const token = request.headers.get("authorization");

    if (token !== `Bearer ${process.env.STORAGE_TOKEN}`) {
      throw new Error(`Unauthorized ${type} for ${key}`);
    }
  },
});

await serve({ port: 3000, fetch });

You can pass the same handler to APIs such as Bun.serve, Deno.serve, or a compatible serverless runtime.

Warning

Always authenticate and authorize requests before exposing a storage handler. The protocol supports listing, writing, deleting, and clearing data; an unprotected endpoint grants broad access to the underlying storage.

#Options

  • authorize(request): Runs before every supported operation. It receives { request, key, type }, where type is "read" or "write". Throw to reject the request.
  • resolvePath(request): Overrides how the request path is converted to a storage key. It receives the Fetch Request.

Errors thrown by authorize become 401 responses unless the thrown error has a numeric status property.

#Connect with the HTTP driver

client.ts
import { createStorage } from "unstorage";
import httpDriver from "unstorage/drivers/http";

const storage = createStorage({
  driver: httpDriver({
    base: "http://localhost:3000",
    headers: {
      authorization: `Bearer ${process.env.STORAGE_TOKEN}`,
    },
  }),
});

await storage.setItem("messages:1", { text: "Hello" });
const message = await storage.getItem("messages:1");

See the HTTP driver documentation for per-request headers, raw values, and TTL options.

#Protocol

Paths map to normalized storage keys. A path ending in / or : is treated as a base for list and clear operations.

MethodOperationResponse
HEAD /keyhasItem(key) and getMeta(key)200 when found, 404 otherwise
GET /keygetItem(key)Serialized value, or 404
GET /base/getKeys(base)JSON array of keys
PUT /keysetItem(key, body)OK
DELETE /keyremoveItem(key)OK
DELETE /base/clear(base)OK

For binary data:

  • send Accept: application/octet-stream with GET to use getItemRaw;
  • send Content-Type: application/octet-stream with PUT to use setItemRaw.

The HTTP driver sends the ttl transaction option as an x-ttl header. When metadata contains mtime or ttl, the handler exposes it through last-modified, x-ttl, and cache-control response headers.