npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

spicedb-embedded

v0.6.0

Published

Embedded SpiceDB for TypeScript/Node.js — embedded authorization using the standard gRPC API

Readme

spicedb-embedded

Sometimes you need a simple way to run access checks without spinning up a new service. This library provides an embedded version of SpiceDB in various languages. Each implementation is based on a C-shared library (compiled from the SpiceDB source code) with a very thin FFI binding on top of it. This means that it runs the native SpiceDB code within your already-running process.

import { v1, EmbeddedSpiceDB } from "spicedb-embedded";

const schema = `definition user {} definition document { relation reader: user permission read = reader }`;
const rel = v1.Relationship.create({
  resource: v1.ObjectReference.create({
    objectType: "document",
    objectId: "readme",
  }),
  relation: "reader",
  subject: v1.SubjectReference.create({
    object: v1.ObjectReference.create({
      objectType: "user",
      objectId: "alice",
    }),
  }),
});

const spicedb = await EmbeddedSpiceDB.start(schema, [rel]);
const resp = await spicedb.permissions().promises.checkPermission(
  v1.CheckPermissionRequest.create({
    resource: v1.ObjectReference.create({
      objectType: "document",
      objectId: "readme",
    }),
    permission: "read",
    subject: v1.SubjectReference.create({
      object: v1.ObjectReference.create({
        objectType: "user",
        objectId: "alice",
      }),
    }),
  })
);
spicedb.close();

Who should consider using this?

If you want to spin up SpiceDB, but don't want the overhead of managing another service, this might be for you.

If you want an embedded server for your unit tests and don't have access to Docker / Testcontainers, this might be for you.

If you have a schema and set of permissions that are static / readonly, this might be for you.

Who should avoid using this?

If you live in a world of microservices that each need to perform permission checks, you should almost certainly spin up a centralized SpiceDB deployment.

If you want visibility into metrics for SpiceDB, you should avoid this.

How does storage work?

The default datastore is "memory" (memdb). If you use this datastore, keep in mind that it will reset on each app startup. This is a great option if you can easily provide your schema and relationships at runtime. This way, there are no external network calls to check relationships at runtime.

If you need a longer term storage, you can use any SpiceDB-compatible datastores.

import { EmbeddedSpiceDB } from "spicedb-embedded";

// Run migrations first: spicedb datastore migrate head --datastore-engine postgres --datastore-conn-uri "postgres://..."
const schema = `definition user {} definition document { relation reader: user permission read = reader }`;
const spicedb = await EmbeddedSpiceDB.start(schema, [], {
  datastore: "postgres",
  datastore_uri: "postgres://user:pass@localhost:5432/spicedb",
});
// Use full Permissions API (writeRelationships, checkPermission, etc.)
spicedb.close();

Running code written in Go compiled to a C-shared library within my service sounds scary

It is scary! Using a C-shared library via FFI bindings introduces memory management in languages that don't typically have to worry about it.

That being said, the SpiceDB code still runs in a Go runtime with garbage collection, which is where the vast majority of time is spent. To help mitigate some of the risk, the FFI layer is kept as straightforward as possible. protobuf is marshalled and unmarshalled at the FFI <--> language runtime boundary in a standardized way. After unmarshalling, requests are sent directly to the SpiceDB server, and responses are returned directly back to the language runtime (after marshalling).

Comparison with SpiceDB WASM

SpiceDB also provides a WebAssembly (WASM) build used in the Authzed Playground.

The WASM only provides a small subset of the functionality of SpiceDB, but it has the advantage of working within the context of a browser.

When to use this package: Node.js applications that want access to full set of APIs that SpiceDB offers.

When to use WASM: Browser-based tools.

Installation

npm install spicedb-embedded

Only the native binary for your platform is installed (via optional dependencies: spicedb-embedded-linux-x64, spicedb-embedded-linux-arm64, spicedb-embedded-darwin-arm64, spicedb-embedded-win32-x64).

Or from source (requires Go with CGO; build and test use the same prebuilds layout as the published package):

mise run shared-c-build
./scripts/stage-all-prebuilds.sh
cd node && npm install && npm run build && npm test

Override the library location with SPICEDB_LIBRARY_PATH if needed. To test the exact tarball you would publish: cd node && npm pack, then install the resulting .tgz in another directory.

Usage

import { v1, EmbeddedSpiceDB } from "spicedb-embedded";

const {
  ObjectReference,
  Relationship,
  SubjectReference,
  CheckPermissionRequest,
  Consistency,
  CheckPermissionResponse,
  CheckPermissionResponse_Permissionship,
} = v1;

const schema = `
definition user {}

definition document {
    relation reader: user
    permission read = reader
}
`;

const rel = Relationship.create({
  resource: ObjectReference.create({
    objectType: "document",
    objectId: "readme",
  }),
  relation: "reader",
  subject: SubjectReference.create({
    object: ObjectReference.create({ objectType: "user", objectId: "alice" }),
  }),
});

const spicedb = await EmbeddedSpiceDB.start(schema, [rel]);

try {
  const response = await spicedb.permissions().promises.checkPermission(
    CheckPermissionRequest.create({
      consistency: Consistency.create({
        requirement: { oneofKind: "fullyConsistent", fullyConsistent: true },
      }),
      resource: ObjectReference.create({
        objectType: "document",
        objectId: "readme",
      }),
      permission: "read",
      subject: SubjectReference.create({
        object: ObjectReference.create({
          objectType: "user",
          objectId: "alice",
        }),
      }),
    })
  );

  const allowed =
    response.permissionship ===
    CheckPermissionResponse_Permissionship.HAS_PERMISSION;
} finally {
  spicedb.close();
}

API

  • EmbeddedSpiceDB.start(options?) — Start an instance without bootstrapping schema or relationships (async).
  • EmbeddedSpiceDB.start(schema, relationships?, options?) — Start an instance and bootstrap it with schema and optional relationships (async).
  • permissions() — Permissions service client (CheckPermission, WriteRelationships, ReadRelationships, etc.). Use .promises for async/await.
  • schema() — Schema service client (ReadSchema, WriteSchema, ReflectSchema, etc.).
  • watch() — Watch service client for relationship changes.
  • close() — Dispose the instance and close the channel.

Use types from v1 (re-exported from @authzed/authzed-node) for ObjectReference, SubjectReference, Relationship, etc.

SpiceDBStartOptions

import { EmbeddedSpiceDB, SpiceDBStartOptions } from "spicedb-embedded";

const options: SpiceDBStartOptions = {
  datastore: "memory", // or "postgres", "cockroachdb", "spanner", "mysql"
  datastore_uri: "postgres://user:pass@localhost:5432/spicedb", // required for remote
  spanner_credentials_file: "/path/to/key.json", // Spanner only
  spanner_emulator_host: "localhost:9010", // Spanner emulator
  mysql_table_prefix: "spicedb_", // MySQL only (optional)
  metrics_enabled: false, // default; set true to enable Prometheus metrics
};

const spicedb = await EmbeddedSpiceDB.start(schema, [], options);

Building & Testing

mise run shared-c-build
cd node
npm install
npm run build
npm test

Or from the repo root: mise run node-test