Skip to content

Storages

These are some kind of data stores. Their main use is in plugins (for example, sessions).

Adapters

GramIO has many ready-made adapters, but you can also write your own!

How to write my own storage adapters

It is very simple to write your adapter!

It is enough to return the object with the required methods and use the methods of the solution you have chosen for the adapter. (for example, ioredis)

ts
import type { Storage } from "@gramio/storage";
import ThirdPartyStorage, { type ThirdPartyStorageOptions } from "some-library";

export interface MyOwnStorageOptions extends ThirdPartyStorageOptions {
    /** add new property to options */
    some?: number;
}

export function myOwnStorage(options: MyOwnStorageOptions = {}): Storage {
    const storage = new ThirdPartyStorage(options);

    return {
        async get(key) {
            const data = await storage.get(key);

            return data ? JSON.parse(data) : undefined;
        },
        async has(key) {
            return storage.has(key);
        },
        async set(key, value) {
            await storage.set(key, JSON.stringify(value));
        },
        async delete(key) {
            return storage.delete(key);
        },
    };
}

IMPORTANT

If you want to publish your adapter, we recommend that you follow the convention and name it starting with gramio-storage and add gramio + gramio-storage keywords in your package.json

How to use storage adapters in my own plugin

It is also very easy to work with storage adapters in your plugin!

Everything we need is already in @gramio/storage.

ts
import { Plugin } from "gramio";
import { type Storage, inMemoryStorage } from "@gramio/storage";

export interface MyOwnPluginOptions {
    storage?: Storage;
}

export function myOwnPlugin(options: MyOwnPluginOptions = {}) {
    // use in memory storage by default
    const storage = options.storage ?? inMemoryStorage();

    return new Plugin("gramio-example");
}

IMPORTANT

You can scaffold this example by create-gramio-plugin

Type-safe storage with generics

All storage adapters support a generic type parameter Storage<Data> that provides type safety for keys and values. This enables TypeScript to infer the correct value type based on the key you're accessing.

Basic usage

ts
import { 
inMemoryStorage
} from "@gramio/storage";
interface UserData {
username
: string;
email
: string;
age
: number;
} const
storage
=
inMemoryStorage
<UserData>();
await
storage
.
set
("username", "john_doe");
await
storage
.
set
("email", "john@example.com");
const
username
= await
storage
.
get
("username"); // string | undefined

Template literal types

Storage<Data> works seamlessly with TypeScript's template literal types, allowing you to define dynamic key patterns:

ts
import { 
inMemoryStorage
} from "@gramio/storage";
type
Data
=
Record
<`user:${number}`, {
name
: string;
age
: number }> &
Record
<`session:${string}`, {
token
: string;
expires
: number }>;
const
storage
=
inMemoryStorage
<
Data
>();
await
storage
.
set
("user:1", {
name
: "Alice",
age
: 30 });
await
storage
.
set
("session:abc123", {
token
: "xyz",
expires
: 1234567890 });
const
user
= await
storage
.
get
("user:1");
const
session
= await
storage
.
get
("session:abc123");

Complex type unions

You can combine multiple record types for different key patterns:

ts
import { 
inMemoryStorage
} from "@gramio/storage";
type
StorageSchema
=
Record
<`counter:${string}`, number> &
Record
<`flag:${string}`, boolean> &
Record
<`data:${string}`, {
value
: string;
timestamp
: number }>;
const
storage
=
inMemoryStorage
<
StorageSchema
>();
await
storage
.
set
("counter:views", 42);
await
storage
.
set
("flag:enabled", true);
await
storage
.
set
("data:config", {
value
: "test",
timestamp
:
Date
.
now
() });
const
views
= await
storage
.
get
("counter:views"); // number | undefined

This type safety works across all storage adapters (in-memory, Redis, Cloudflare KV, etc.) and helps prevent runtime errors by catching type mismatches at compile time.

Adapter versions

AdapterLatest version
@gramio/storage (In Memory)2.0.1
@gramio/storage-redis1.0.5
@gramio/storage-cloudflare0.0.2
@gramio/storage-sqlite0.0.2

The Storage interface in v2.0.x uses a generic Data type with typed keys across all methods (get, set, has, delete). All adapters serialize keys via String() for backward compatibility. This is the foundation for the type-safe storage generics described above.

List

In Memory

npmnpm downloadsJSRJSR Score

Installation
sh
npm install @gramio/storage
sh
yarn add @gramio/storage
sh
pnpm add @gramio/storage
sh
bun add @gramio/storage
Usage
  1. With default Map
ts
import { 
inMemoryStorage
} from "@gramio/storage";
const
storage
=
inMemoryStorage
();
  1. Provide your own Map
ts
import { 
inMemoryStorage
, type
InMemoryStorageMap
} from "@gramio/storage";
const
map
:
InMemoryStorageMap
= new
Map
();
const
storage
=
inMemoryStorage
(
map
);

Redis

npmnpm downloadsJSRJSR Score

Installation
sh
npm install @gramio/storage-redis ioredis
sh
yarn add @gramio/storage-redis ioredis
sh
pnpm add @gramio/storage-redis ioredis
sh
bun add @gramio/storage-redis ioredis
Usage
  1. Provide ioredis options to the redisStorage function
ts
import { 
redisStorage
} from "@gramio/storage-redis";
const
storage
=
redisStorage
({
host
:
process
.
env
.
REDIS_HOST
,
});
  1. Provide ioredis instance to the redisStorage function
ts
import { 
redisStorage
} from "@gramio/storage-redis";
import {
Redis
} from "ioredis";
const
redis
= new
Redis
({
host
:
process
.
env
.
REDIS_HOST
,
}); const
storage
=
redisStorage
(
redis
);
Tips
  • You can set the DEBUG env to ioredis:* to print debug info:
bash
DEBUG=ioredis:* npm run start

and it will looks like this:

bash
  ioredis:redis write command[::1:6379]: 0 -> get([ '@gramio/scenes:617580375' ]) +187ms
  ioredis:redis write command[::1:6379]: 0 -> set([ '@gramio/scenes:617580375', '{"name":"scene-name","state":{},"stepId":0,"previousStepId":0,"firstTime":false}' ]) +1ms
AnotherRedisDesktopManager

SQLite

npmnpm downloads

TIP

Supports both Bun (bun:sqlite) and Node.js (node:sqlite). The correct implementation is auto-selected based on your runtime.

Installation
bun
bash
bun install @gramio/storage-sqlite
Usage
  1. Pass a filename to create a new database
ts
import { sqliteStorage } from "@gramio/storage-sqlite";

const storage = sqliteStorage({ filename: "bot-data.db" });
  1. Pass an existing Bun SQLite Database instance
ts
import { sqliteStorage } from "@gramio/storage-sqlite";
import { Database } from "bun:sqlite";

const db = new Database("bot-data.db");
const storage = sqliteStorage({ db });
  1. With TTL (automatic key expiry)
ts
import { sqliteStorage } from "@gramio/storage-sqlite";

const storage = sqliteStorage({
    filename: "bot-data.db",
    $ttl: 3600, // keys expire after 1 hour
});
Options
  • filename — Path to the SQLite file
  • db — Alternatively, pass a pre-existing Database instance
  • $ttl — Optional TTL in seconds for automatic expiry
  • tableName — Custom table name (defaults to "gramio_storage")

Cloudflare KV

npmnpm downloadsJSRJSR Score

Installation
sh
npm install @gramio/storage-cloudflare
sh
yarn add @gramio/storage-cloudflare
sh
pnpm add @gramio/storage-cloudflare
sh
bun add @gramio/storage-cloudflare
Usage
  1. Configure Cloudflare KV namespace

  2. Provide Cloudflare KV namespace to the cloudflareStorage function

ts
import { cloudflareStorage } from "@gramio/storage-cloudflare";

const storage = cloudflareStorage(Env.CLOUDFLARE_KV_NAMESPACE);