unstorage: a key-value API over memory, Redis, Cloudflare KV and dozens more drivers
💾 Unstorage provides an async Key-Value storage API with conventional features like multi driver mounting, watching and working with metadata, dozens of built-in drivers and a tiny core.
At a glance
- What is it?
- unstorage wraps many storage backends behind one async key-value interface with mount points, metadata, watching and snapshots. The core is small, the driver list is long, and the current npm line is still on 1.x while 2.0 sits in alpha.
- Who is it for?
- Adopt unstorage when your storage backends already exist and you want one API in front of them, especially if you mount several at once or need metadata and watching without writing that layer yourself. Do not adopt it if you need durability guarantees, transactions or query semantics that your backend does not already provide, because unstorage is a thin layer and does not add them.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem unstorage solves: one key-value API over many backends
Most applications end up with storage scattered across more than one place. A session blob lives in Redis, an uploaded asset in an object store, a cache entry in memory, and a feature flag in Cloudflare KV. Each of those has its own client, its own error shape and its own idea of what a key looks like. unstorage's answer is a single async key-value interface that sits in front of all of them, with a default in-memory backend so the same code runs before any real backend is wired up. The README describes it as an async Key-Value storage API with multi driver mounting, watching, metadata, dozens of built-in drivers and a tiny core, and it targets browser, Node.js and Workers environments from the same package. That last point matters more than it sounds: the same storage calls can run in a Worker at the edge and in a Node process on a server, which is awkward when you are juggling four vendor SDKs. The audience is application and framework developers who want the storage abstraction to be the boring part. It is not aimed at people who need a database. There is no query planner, no secondary index and no transaction coordinator here; the README lists key-value operations, snapshots and an HTTP server, nothing more.
How the storage layer is put together: drivers, mount points and keys
The mechanism is a driver registry plus a mount table. A driver is an object implementing the key-value operations against one backend, and createStorage accepts options that decide which driver serves which prefix. Mounting is described as Unix-style, so a key like foo:bar can be routed to one driver while another prefix routes elsewhere, and the default in-memory driver catches everything that is not mounted. Values are serialized and deserialized as JSON automatically, and the README also mentions binary and raw value support for cases where JSON is the wrong container. Metadata is part of the API surface rather than something you bolt on, which is how the watcher can report changes without the driver inventing its own event format. Snapshots and hydration let you capture the state of a storage instance and restore it elsewhere, which is useful for tests and for moving between an in-memory instance and a real backend. The package is published as ESM only (the package.json sets type to module and points main at ./dist/index.mjs) with subpath exports for ./drivers/*, ./server and ./tracing, so drivers are imported individually rather than all at once. That is what keeps the core small: you pay for the drivers you import.
Installing unstorage and reading and writing your first key
The README gives three package manager commands. Pick the one that matches your project; the package name is unstorage in all of them.
npm install unstorage
# or
pnpm add unstorage
# or
yarn add unstorageOnce installed, createStorage returns an instance with no configuration. With no options, the README states that storage defaults to in-memory, so this snippet runs without any backend running anywhere.
import { createStorage } from "unstorage";
const storage = createStorage(/* opts */);
await storage.getItem("foo:bar"); // or storage.getItem('/foo/bar')The comment in the README is worth reading twice: the colon form and the slash form of the same key are both accepted, so foo:bar and /foo/bar address the same entry. If you run the snippet against a fresh instance, getItem resolves to null because nothing has been written yet. Writing follows the same shape with setItem, and because serialization is automatic you pass the JavaScript value, not a stringified version of it. For a first real use, mount a second driver under a prefix and confirm that reads route correctly; the drivers documentation at unstorage.unjs.io lists what each one needs in the way of connection options. The repository's .env.example shows the environment variables the test suite expects for hosted drivers such as VITE_UPSTASH_REDIS_REST_URL, VITE_UPSTASH_REDIS_REST_TOKEN, VITE_VERCEL_BLOB_READ_WRITE_TOKEN and VITE_CLOUDFLARE_ACC_ID, which tells you the shape of the credentials these drivers take even though the file is meant for the project's own tests.
Where unstorage stops: no durability, no transactions, no queries
The abstraction is thin on purpose, and that is also its main limitation. unstorage does not make a backend do something the backend cannot do. If your Redis instance is configured without persistence, unstorage will not save you. If your object store has eventual consistency, getItem can return a stale value and unstorage has no read-your-writes mode to offer. There are no transactions across mount points either: two writes to two drivers are two independent operations, and nothing in the README suggests otherwise. That makes unstorage the wrong tool for anything resembling a ledger, a queue with delivery guarantees, or a relational workload. It is also the wrong choice when you only ever talk to one backend. If your whole application uses Redis and nothing else, adding unstorage inserts a translation layer between you and the client you already understand, and you inherit its serialization rules. The JSON round-trip is another boundary to keep in mind. Values are serialized and deserialized automatically, so a value that does not survive a JSON round-trip (a class instance, a Map, a BigInt) will not come back as what you put in unless you use the raw or binary paths the README mentions.
unstorage compared with talking to Redis or S3 directly
The honest alternative is skipping the abstraction. A team using one backend would import ioredis or the official object store SDK and call it directly, which gives access to the full feature set of that service: Redis pipelining, Lua scripts, pub/sub, TTL semantics, and the vendor's own error types. unstorage exposes a key-value subset, so those features are either unavailable or reachable only through driver-specific escape hatches. The difference in approach is where the complexity sits. Direct SDK usage puts backend-specific code in your application and ties that code to one service; unstorage puts a uniform interface in your application and moves the backend-specific code into a driver you import. The trade is real in both directions. If you mount two or three backends and want one code path, or you need the same code to run in a Worker and in Node, the abstraction earns its place. If you need transactions, queries or vendor-specific features, the abstraction is a cost with no matching benefit. The repository's own devDependencies hint at how wide the driver surface is: Azure App Configuration, Cosmos DB, Data Tables, Key Vault and Blob Storage, Deno KV, PGlite, libSQL, Netlify Blobs, PlanetScale, Upstash Redis, Vercel Blob and Cloudflare Workers types all appear there, which is a lot of surface to keep aligned with upstream API changes.
Release cadence, version choice and what MIT actually covers
The version you get from npm and the version in the repository are not the same right now. The latest release listed is v1.17.5 from 2026-03-26, while package.json in the repository reads 2.0.0-alpha.10 and the release script publishes with the alpha tag. The README documents a nightly channel as well: unstorage-nightly, which you opt into either by aliasing the dependency or by adding a resolutions entry. That gives three tracks (stable 1.x, 2.0 alpha, nightly) and the README does not describe a migration path between them. The last push to the repository was on 2026-09-24, so work is ongoing, but an alpha line means the API of 2.0 can still move. Upgrade cost is mostly the driver surface. Each driver wraps an external SDK, and those SDKs release on their own schedule; the repository carries a renovate.json, which suggests dependency bumps are automated, but a major bump in an underlying client can still change driver behaviour in ways the changelog does not spell out. The licence is MIT, which is permissive and short. That covers the unstorage code. It does not cover the services your drivers connect to, and it says nothing about the terms you agreed to with Redis, Cloudflare, Vercel or Azure; those are separate agreements and are where the real constraints usually live.
Contributing to unstorage and running its tests locally
The README's contribution section is short and specific. Clone the repository, install dependencies with pnpm, and use pnpm dev to start a watcher. The package.json scripts confirm the tooling: dev runs vitest, test runs lint, type checks and vitest with coverage, and build runs a driver generation step before obuild. The gen-drivers script regenerates the driver entry points, which is why drivers are imported from ./drivers/* rather than from the root export.
pnpm install
pnpm dev
pnpm testIf you add a driver, the build step is not optional: pnpm build runs pnpm gen-drivers first, so a driver that is not picked up by the generator will not appear in dist/drivers. The README asks contributors to run pnpm test before pushing, and that command includes lint and a type check, so a driver with a loose type will fail before it reaches review.
Editorial conclusion
Adopt unstorage when your storage backends already exist and you want one API in front of them, especially if you mount several at once or need metadata and watching without writing that layer yourself. Do not adopt it if you need durability guarantees, transactions or query semantics that your backend does not already provide, because unstorage is a thin layer and does not add them. Before committing, verify which version you are installing (the package.json in the repository reads 2.0.0-alpha.10 while the latest stable release is v1.17.5), confirm that your target driver is present in the built dist/drivers output, and check whether the driver you need is documented for the runtime you deploy to.
Frequently asked questions
What is unstorage used for?
It provides an async key-value storage API that sits in front of many backends, with features such as multi driver mounting, watching, metadata, snapshots and an HTTP server. It is designed to run in the browser, Node.js and Workers environments.
How do I install unstorage?
The README gives npm install unstorage, pnpm add unstorage and yarn add unstorage. After that, createStorage returns an instance that defaults to in-memory storage when no options are passed.
Which version of unstorage should I install?
The latest release listed is v1.17.5, while the repository's package.json reads 2.0.0-alpha.10 and the release script publishes with the alpha tag. The README also documents a nightly channel published as unstorage-nightly.
Does unstorage work with Redis and Cloudflare KV?
The README states there are dozens of built-in drivers, and the repository's devDependencies include Upstash Redis and Cloudflare Workers types among many others. Drivers are imported individually from the ./drivers/* export path.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/unjs-unstorage)