Skip to content

Getting Started

Monorise is an open-source DynamoDB single-table toolkit that powers the core data layer for applications built on DynamoDB. It provides a shared data model (schemas + relationships), a ready-made API surface (entities, mutuals, tags), and background processors to keep denormalized access patterns in sync.

What it solves

  • Single-table DynamoDB modeling without hand-writing complex queries.
  • Relational-style access via Entity, Mutual, and Tag concepts.
  • Event-driven maintenance (mutual/tag/prejoin processors + replication).
  • Shared schema + types across backend and frontend.

Prerequisites

  • Node.js 20+
  • npm 10+
  • AWS account/infrastructure context for runtime integration (SST + DynamoDB)

Installation

Install the combined package:

bash
npm install monorise zod

Peer dependencies

Depending on which parts of monorise you use, you may need additional peer dependencies:

Use casePeer dependencyInstall
Backend APIhononpm install hono
Frontend (React)react, react-domIncluded with Next.js/CRA
Infrastructuresstnpm install sst

TIP

Frontend-only projects (e.g., a Next.js app consuming the monorise API) only need monorise and zod — no need to install hono or sst.

Individual packages (alternative)

bash
npm install @monorise/base @monorise/core @monorise/cli zod hono
npm install @monorise/react   # optional: React SDK
npm install @monorise/sst sst # optional: SST v3 infra module

Quickstart

Initialize a project skeleton (creates monorise.config.ts and a starter entity):

bash
npx monorise init

Example entity config:

ts
import { createEntityConfig } from 'monorise/base';
import { z } from 'zod/v4';

const baseSchema = z
  .object({
    displayName: z.string().min(1),
    email: z.string().email(),
  })
  .partial();

const createSchema = z.object({
  displayName: z.string().min(1),
  email: z.string().email(),
});

const config = createEntityConfig({
  name: 'user',
  displayName: 'User',
  baseSchema,
  createSchema,
  searchableFields: ['displayName', 'email'],
  uniqueFields: ['email'],
});

export default config;

Generate monorise artifacts from your config:

bash
npx monorise build

For watch mode while developing entity configs:

bash
npx monorise dev

This generates .monorise/config.ts and .monorise/handle.ts for runtime wiring.

Project config (monorise.config.ts)

The monorise.config.ts file at your project root tells the CLI where to find your entity configs and custom routes:

ts
export default {
  // Directory containing your entity config files
  configDir: './monorise/configs',

  // (Optional) Hono app instance for custom API routes (mounted at /core/app/*)
  customRoutes: './src/routes',
};
FieldTypeRequiredDescription
configDirstringYesPath to directory containing entity config .ts files
customRoutesstringNoPath to a Hono app module for custom routes

TIP

The CLI auto-detects whether your project uses the combined monorise package or scoped @monorise/* packages and generates the correct import paths in .monorise/handle.ts accordingly.

Entity config directory

The configDir should contain one .ts file per entity, each exporting a default createEntityConfig result:

monorise/configs/
  user.ts
  organisation.ts
  order.ts

Custom routes

The customRoutes file must default-export a Hono app instance. These routes are mounted under /core/app/*:

ts
import { Hono } from 'hono';

const app = new Hono();

app.get('/health', (c) => c.json({ status: 'ok' }));

app.post('/custom-action', async (c) => {
  // Access DI container, entity services, etc.
  const body = await c.req.json();
  return c.json({ result: 'done' });
});

export default app;

Generated code and type safety

When you run monorise build or monorise dev, the CLI generates .monorise/config.ts which includes:

  • An Entity enum with all your entity names
  • TypeScript types inferred from each entity's baseSchema
  • An EntitySchemaMap interface mapping entity types to their schemas
  • Module augmentation declarations that extend monorise/base types

The module augmentation is what makes the entire system type-safe. For example, when you call useEntity(Entity.USER, id), the returned entity.data is strongly typed with your user schema fields — not any.

ts
// Auto-generated in .monorise/config.ts
declare module 'monorise/base' {
  export enum Entity {
    USER = 'user',
  }
  export type UserType = z.infer<typeof userConfig.finalSchema>;
  export interface EntitySchemaMap {
    [Entity.USER]: UserType;
  }
}

INFO

You never need to write this manually — the CLI generates it from your entity configs.

Deploy with SST v3

Monorise is designed to run on AWS with SST v3. The monorise/sst module provisions everything you need — API Gateway, DynamoDB table, EventBridge bus, SQS queues for processors, and DynamoDB streams for replication — in a single construct.

bash
npm install sst

In your sst.config.ts:

ts
/// <reference path="./.sst/platform/config.d.ts" />
export default $config({
  app(input) {
    return {
      name: 'my-app',
      removal: input?.stage === 'production' ? 'retain' : 'remove',
      home: 'aws',
    };
  },
  async run() {
    const { monorise } = await import('monorise/sst');

    const { bus, api, table, alarmTopic } = new monorise.module.Core('core', {
      allowOrigins: ['http://localhost:3000'],
    });

    // Link to your frontend
    new sst.aws.Nextjs('Web', {
      link: [api],
    });
  },
});

What monorise.module.Core creates

ResourceDescription
apiAPI Gateway v2 with CORS, routing to Hono Lambda
tableDynamoDB single table with GSIs and replication indexes
busEventBridge bus for entity events
alarmTopicSNS topic for processor error alerts
Mutual processorSQS + Lambda for mutual relationship sync
Tag processorSQS + Lambda for tag index sync
Prejoin processorSQS + Lambda for computed relationship sync
Replication processorDynamoDB stream + Lambda for denormalized data sync
CloudWatch dashboardPre-built dashboard with Lambda metrics, DLQ depth, and table stats

Configuration options

ts
new monorise.module.Core('core', {
  allowOrigins: ['https://myapp.com'],  // CORS origins
  allowHeaders: ['x-custom-header'],     // Additional CORS headers
  tableTtl: 'expiresAt',                // DynamoDB TTL attribute name
  slackWebhook: 'https://hooks...',     // Slack alerts for processor errors
  configRoot: './services/api',          // Custom config root path
});

For the full SST SDK reference including QFunction, see the SST SDK page.

Development

SST's dev mode works seamlessly with monorise. The monorise.module.Core constructor automatically registers a dev command that runs monorise dev in watch mode:

bash
npx sst dev

This starts your local dev environment with live Lambda functions and auto-regenerating monorise config.

Before you start building

Read the Best Practices guide first — especially the edge-auth proxy pattern. How you connect your frontend to the monorise API Gateway has significant security implications.

Common commands

bash
npx monorise init     # scaffold a new project
npx monorise dev      # watch mode — regenerates on config changes
npx monorise build    # one-time build

Released under the MIT License.