This is `canary` version of documentation. It's still under construction and review.
Rescale logoNEMO

Storage (shared context)

Storage (shared context) between functions across the execution chain

NEMO provides a storage (shared context) that allows you to share data between functions in the middleware execution chain. This can be useful when you need to pass data between functions or store data that needs to be accessed by multiple functions.

By default it operates using in-memory storage, but you can extend it with your own storage solution or database of choice.

Warning! Be careful using database as storage adapter, as it can slow down the execution chain and make your site's TTFB skyrocket.

Recommendation: Use KV databases/solutions like Redis, Vercel EdgeConfig etc.

Read more about good practices

Usage example

Below you can see an example of how to use the shared context in your middleware functions.

Remember that each request's middleware execution is a separate event instance, so the context is not shared between different requests.

_middleware.ts
import type { NextMiddleware } from "@rescale/nemo";
 
const example: NextMiddleware = async (req, { storage }) => {
  let user = undefined; 
 
  if(!storage.has('user')) { 
    user = await fetchUser(); 
    storage.set('user', user); 
  } else { 
    user = storage.get('user'); 
  } 
 
  if(!user) {
    return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
  }
}

Custom Storage adapter

You can extend the default in-memory storage with your own storage adapter. To do this, you need to create a class that implements the StorageAdapter interface.

StorageAdapter.ts
import { StorageAdapter } from "@rescale/nemo";
 
export class CustomStorageAdapter extends StorageAdapter {
  // Implement required methods
  async get<T>(key: string): T | undefined {
    // Your implementation
    return undefined;
  }
 
  async set<T>(key: string, value: T): void {
    // Your implementation
  }
 
  async has(key: string): boolean {
    // Your implementation
    return false;
  }
 
  async delete(key: string): boolean {
    // Your implementation
    return false;
  }
 
  async clear(): void {
    // Your implementation
  }
 
  // Implement other required methods
  entries(): IterableIterator<[string, unknown]> {
    // Your implementation
    return [][Symbol.iterator]();
  }
 
  keys(): IterableIterator<string> {
    // Your implementation
    return [][Symbol.iterator]();
  }
 
  values(): IterableIterator<unknown> {
    // Your implementation
    return [][Symbol.iterator]();
  }
 
  get size(): number {
    // Your implementation
    return 0;
  }
}

After creating your storage adapter, you can use it by passing it to the NEMO constructor.

middleware.ts
import { NEMO } from "@rescale/nemo";
import { CustomStorageAdapter } from "./StorageAdapter";
 
export const middleware = createNEMO(middlewares, globalMiddleware, {
  storage: new CustomStorageAdapter()
});

On this page