npm.io
2.0.1 • Published 2d ago

neogma

Licence
MIT
Version
2.0.1
Deps
4
Size
1022 kB
Vulns
0
Weekly
0
Stars
158

neogma logo

The Neo4j OGM that feels like writing plain TypeScript

Define models with decorators, run fully type-safe queries against them, eager load relationships in a single trip, and let TypeScript catch your mistakes before Neo4j does

npm version npm downloads TypeScript License Tests


What's new in v2

v2 replaces verbose factory configs with decorators you can read at a glance:

  • @Node, @PrimaryKey, @Property, @Relationship -- define models as plain classes
  • TypeBox validation built in -- powerful schemas, no extra dependencies
  • Zero boilerplate -- no more separate *Properties, *Instance, or *RelatedNodes interfaces
  • Both decorator styles -- TC39 standard (recommended) and legacy experimental
  • @neogma/nest -- first-class NestJS module with forRoot/forRootAsync, model DI via forFeature, and automatic connection lifecycle

v2 is fully backwards compatible. Existing v1 code keeps working, but we recommend migrating for the improved DX. See the migration guide for step-by-step instructions.

Looking for v1? Source is on the release/v1 branch, docs at themetalfleece.github.io/neogma.


Why Neogma?

Most Neo4j libraries make you choose between convenience and control. Neogma gives you both:

  • Type-safe end to end - define a model once, get compile-time checks on creates, queries, and relationships
  • Decorator-based models - plain classes with @Node, @Property, @Relationship -- no boilerplate interfaces
  • Flexible by design - use the OGM for CRUD, the query builder for complex traversals, or drop to raw Cypher when you need to
  • Automatic relationships - create deeply nested graph structures in a single call
  • Eager loading - fetch related nodes in one query, no N+1 surprises
  • Built-in TypeBox validation - schema validation included, nothing extra to install
  • Injection-safe - every user value is a query parameter, never interpolated into Cypher
  • Session and transaction helpers - automatic cleanup, rollback on error, minimal ceremony
  • NestJS ready - first-class integration via @neogma/nest
  • Battle-tested - comprehensive test suite, used in production

Documentation

Full documentation, guides, and API reference at neogma.themetalfleece.dev

For AI/LLM agents, the docs are also available in machine-readable formats:

Installation

npm install neogma
# or
pnpm add neogma
# or
yarn add neogma

Quick Start

import {
  Neogma,
  Node,
  PrimaryKey,
  Property,
  Relationship,
  NodeEntity,
  Type,
} from 'neogma';
import type { Related } from 'neogma';

// Connect to Neo4j
const neogma = new Neogma({
  url: 'bolt://localhost:7687',
  username: 'neo4j',
  password: 'password',
});

// Define models with decorators
@Node({ label: 'Order' })
class OrderNode extends NodeEntity {
  @PrimaryKey(Type.String()) id!: string;
  @Property(Type.String()) status!: string;
}

@Node({ label: 'User' })
class UserNode extends NodeEntity {
  @PrimaryKey(Type.String()) id!: string;

  @Property(Type.String({ minLength: 1 }))
  name!: string;

  @Property(Type.Optional(Type.Number({ minimum: 0 })))
  age?: number;

  @Relationship({ name: 'PLACED', direction: 'out', model: () => OrderNode })
  Orders!: Related<typeof OrderNode>;
}

// Register models (dependency order - referenced models first)
const Orders = neogma.model(OrderNode);
const Users = neogma.model(UserNode);

// Create - TypeScript validates properties at compile time
const user = await Users.createOne({
  id: '1',
  name: 'Alice',
  age: 30,
  Orders: {
    attributes: [{ id: 'order-1', status: 'confirmed' }],
  },
});

// Eager-load relationships in one query
const found = await Users.findOne({
  where: { name: 'Alice' },
  relationships: { Orders: { where: { target: { status: 'confirmed' } } } },
});
console.log(found?.name); // string
console.log(found?.Orders[0].node.status); // string
// console.log(found?.bogusValue);           // TypeScript error

Decorator styles

Neogma supports both TC39 standard decorators (recommended) and legacy experimental decorators.

TC39 decorators (default)

No tsconfig changes needed. Import from neogma:

import { Node, PrimaryKey, Property, Relationship, NodeEntity } from 'neogma';
Legacy experimental decorators

Enable in tsconfig.json:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

Import from neogma/legacy:

import {
  Node,
  PrimaryKey,
  Property,
  Relationship,
  NodeEntity,
} from 'neogma/legacy';

Query Builder

Build complex Cypher queries programmatically:

import { QueryBuilder, BindParam } from 'neogma';

const qb = new QueryBuilder()
  .match({ identifier: 'u', model: Users })
  .where('u.age >= $minAge')
  .match({
    related: [
      { identifier: 'u' },
      { direction: 'out', name: 'PLACED' },
      { identifier: 'o', model: Orders },
    ],
  })
  .return('u.name AS name, count(o) AS orderCount')
  .orderBy('orderCount DESC')
  .limit(10);

const bp = new BindParam({ minAge: 18 });
const { records } = await qb.run(neogma.queryRunner, bp);

Eager Loading

Load related nodes in a single query:

const users = await Users.findMany({
  where: { status: 'active' },
  relationships: {
    Orders: {
      where: { target: { status: 'confirmed' } },
      order: [{ on: 'target', property: 'createdAt', direction: 'DESC' }],
      limit: 5,
      relationships: {
        Items: { limit: 10 },
      },
    },
  },
});

users[0].Orders[0].node.status; // Order property
users[0].Orders[0].relationship; // Relationship properties

NestJS Integration

@neogma/nest provides a dedicated NestJS module with dependency injection, connection lifecycle management, and model registration.

npm install @neogma/nest neogma
# or
pnpm add @neogma/nest neogma

Features:

  • NeogmaModule.forRoot() / forRootAsync() -- configure connection with static options or from ConfigService
  • NeogmaModule.forFeature([...models]) -- register decorated model classes as injectable providers
  • NeogmaService -- injectable service exposing the Neogma instance for raw queries
  • getModelToken() / ModelOf<T> -- type-safe DI token helpers
  • Automatic connection lifecycle (connect on init, close on shutdown)
import { Module } from '@nestjs/common';
import { NeogmaModule } from '@neogma/nest';

@Module({
  imports: [
    NeogmaModule.forRoot({
      connection: {
        url: 'bolt://localhost:7687',
        username: 'neo4j',
        password: 'password',
      },
    }),
    NeogmaModule.forFeature([UserNode, OrderNode]),
  ],
})
export class AppModule {}
import { Injectable, Inject } from '@nestjs/common';
import { getModelToken } from '@neogma/nest';
import type { ModelOf } from '@neogma/nest';

type UserModel = ModelOf<typeof UserNode>;

@Injectable()
export class UserService {
  constructor(@Inject(getModelToken(UserNode)) private Users: UserModel) {}

  async findAll() {
    return this.Users.findMany({});
  }
}

See the NestJS integration docs and the nestjs-app example for full details.


Example Applications

Runnable examples are in the /examples directory:

Example Description
basic-app-decorators TC39 decorator-based models (recommended)
basic-app-legacy-decorators Experimental (legacy) decorator-based models
basic-app-js JavaScript with ModelFactory
nestjs-app NestJS integration with @neogma/nest

Contributing

See DEVELOPMENT.md for setup instructions and development workflow.

Acknowledgements

  • Neogma logo created by Greg Magkos
  • Development was made possible thanks to the open source libraries which can be found in package.json

Keywords