Skip to main content

adapters overview

Storage layer for duck-iam - pick a built-in adapter (Memory, File, Prisma, Drizzle, Redis, HTTP) or implement IamAdapter.IAdapter for custom backends.

What is an adapter?

Adapters are duck-iam's storage layer. They implement IamAdapter.IAdapter, which combines three stores:

Loading diagram...

  • PolicyStore - CRUD for access policies (rules, conditions, combining algorithms)
  • RoleStore - CRUD for roles (permissions, inheritance, scopes)
  • SubjectStore - role assignments, scoped roles, and subject attributes

Every adapter is fully typed against your app's action, resource, role, and scope unions.

import { IamEngine } from '@gentleduck/iam'

const engine = new IamEngine({
  adapter: yourAdapter,
  defaultEffect: 'deny',
  cacheTTL: 60,
})

Built-in adapters

AdapterUse casePersistencePeer dep
MemoryDev, testing, prototypingNone (in-process)None
FileCLIs, dev fixtures, single-process appsJSON on disknode:fs/promises (pluggable)
PrismaProduction w/ PrismaAny Prisma-supported DB@prisma/client
DrizzleProduction w/ DrizzlePG, MySQL, SQLitedrizzle-orm
RedisDistributed deploysRedis-compatible KVioredis or redis
HTTPMicroservices splitRemote APINone (uses fetch)
CustomAny other backendYour choiceYour choice

All adapters are interchangeable. Start with IamMemoryAdapter during development and switch to a database adapter in production without changing engine, builder, or middleware code.


How adapters fit in

import { IamEngine } from '@gentleduck/iam'
import { IamMemoryAdapter } from '@gentleduck/iam/adapters/memory'

// 1. Pick a storage backend
const adapter = new IamMemoryAdapter({ /* seed */ })

// 2. Wrap it in an engine
const engine = new IamEngine({ adapter, defaultEffect: 'deny' })

// 3. Use the engine - same API regardless of adapter
const allowed = await engine.can('user-1', 'read', { type: 'post', attributes: {} })

The engine reads from the adapter on cache miss, then caches policies, roles, and resolved subjects in an LRU with the configured cacheTTL. Adapter writes via engine.admin.* automatically invalidate the relevant caches.

See Comparison & FAQ for selection guidance and answers to common adapter questions.