{
  "generator": {
    "name": "Symvanta",
    "url": "https://symvanta.com"
  },
  "page": {
    "url": "https://symvanta.com/architecture/prisma",
    "title": "Prisma Architecture: How It Actually Works",
    "description": "Prisma Next across 500 Louvain clusters: the SQL expression AST, the contract IR, and the ORM client that compiles queries at runtime, mapped by Symvanta.",
    "datePublished": "2026-07-16",
    "dateModified": "2026-08-22"
  },
  "repository": {
    "name": "prisma/prisma",
    "url": "https://github.com/prisma/prisma",
    "commit": "dd6c12b",
    "license": "Apache-2.0"
  },
  "graph": {
    "modules": 500,
    "dependencyCycles": 27,
    "modularityQ": 0.96,
    "largestCycleFiles": 20,
    "mutuallyRecursiveGroups": 54
  },
  "summaryMarkdown": "Prisma Next is a TypeScript rewrite of Prisma ORM, in Early Access on the default branch of prisma/prisma while Prisma ORM 7 continues from the repository's [`v7` branch](https://github.com/prisma/prisma/tree/v7). It moves the schema off the codegen path and onto a contract-first model: a `.prisma` file compiles to a versioned JSON contract plus TypeScript types, and queries are written against a composable DSL that compiles to SQL at runtime, described in the repo's own [ARCHITECTURE.md](https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/ARCHITECTURE.md). [Symvanta](https://symvanta.com) indexed the monorepo and grouped its symbols into 500 functional clusters (modularity Q=0.96); the map flags a display cap at that number, so a monorepo laid out in ten numbered package groups carries more clusters than the map prints. The largest, 1,217 symbols anchored on `AnyExpression`, is the SQL expression AST every query plan is built from, and the ORM client that builds those plans calls into it 67 times while it calls back 62 times, the heaviest pair of edges on the map.",
  "subsystems": [
    {
      "name": "SQL Relational AST",
      "descriptionMarkdown": "The largest cluster at 1,217 symbols: the query AST the SQL family shares, under [`packages/2-sql/4-lanes/relational-core/src/ast/`](https://github.com/prisma/prisma/tree/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/4-lanes/relational-core/src/ast). `AnyExpression`, `Expression`, `AstNode`, and `ColumnRef` define the node types; `AstNode.freeze` and `frozenArrayCopy` make every node immutable once built, which is what lets one plan be inspected, rewritten by middleware, and rendered without copying. Its 62 calls into the ORM client are the return leg of the pair described above, and it reaches into a smaller `Expression Handling` cluster 29 more times."
    },
    {
      "name": "SQL ORM Client Collections",
      "descriptionMarkdown": "472 symbols in [`packages/3-extensions/sql-orm-client/`](https://github.com/prisma/prisma/tree/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client), the layer application code touches. `CollectionImpl` carries the chainable query API (`.where()`, `.include()`, `.all()`) and `Collection` is the public type over it, `resolveModelTableName` and `domainModelTableInNamespace` map a contract model onto its physical table, and `JunctionThrough` carries many-to-many relations. `ormError`, `OrmCode`, and `OrmSubcode` give every failure here a structured code. This package also holds the repo's largest dependency cycle, 20 files (see Health signals below)."
    },
    {
      "name": "SQL Storage Contract IR",
      "descriptionMarkdown": "735 symbols in [`packages/2-sql/1-core/contract/src/ir/`](https://github.com/prisma/prisma/tree/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/1-core/contract/src/ir): the contract's own model of storage. `SqlStorage`, `SqlNamespace`, `SqlNamespaceEntries`, and `StorageTable` describe what exists in the database, and `PostgresSchema`, `PostgresTableSchemaNode`, and `PostgresDatabaseSchemaNode` specialise that for Postgres. Everything downstream reads the contract through this cluster, which is why `Postgres Migration Tools` calls into it 14 times and `SQL Schema IR` 7 more."
    },
    {
      "name": "SQL Schema IR",
      "descriptionMarkdown": "509 symbols in [`packages/2-sql/1-core/schema-ir/`](https://github.com/prisma/prisma/tree/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/1-core/schema-ir), a second representation aimed at migrations: `SqlTableIR`, `SqlColumnIR`, `SqlSchemaIR`, plus the constraint nodes `SqlCheckConstraintIR`, `SqlForeignKeyIR`, `SqlUniqueIR`, and `SqlIndexIR`. The hub is `defineNonEnumerable`, a twelve-line helper the IR nodes use to attach a derivation-time field that stays out of `JSON.stringify`, out of structural test assertions, and out of spreads, while the one consumer that needs it at plan time still reads it as `node.field`. The contract IR and the schema IR call each other 13 and 7 times, the second-heaviest pair on the map."
    },
    {
      "name": "PSL Syntax Tree",
      "descriptionMarkdown": "615 symbols in [`packages/1-framework/2-authoring/psl-parser/src/syntax/`](https://github.com/prisma/prisma/tree/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/1-framework/2-authoring/psl-parser/src/syntax), a red/green syntax tree of the sort rust-analyzer and Roslyn use: immutable `GreenNode` and `GreenElement` values hold the shape and text, and the red layer (`SyntaxNode`, `SyntaxToken`, `SyntaxElement`) wraps them with absolute offsets and parent links computed on demand. `SyntaxNode.children`, `findChildToken`, and `SourceFile.positionAt` are how the CLI and the language server navigate a `.prisma` file. The cluster has almost no outbound weight (three calls total) because a syntax tree is read by everything and calls almost nothing."
    },
    {
      "name": "Mongo Aggregation Expressions",
      "descriptionMarkdown": "522 symbols in [`packages/2-mongo-family/4-query/query-ast/`](https://github.com/prisma/prisma/tree/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-mongo-family/4-query/query-ast). `MongoAggExpr`, `MongoAggExprNode`, `MongoFilterExpr`, `MongoFieldFilter`, and `MongoAggOperator.of` are the MongoDB half of the same idea the SQL AST implements: a typed expression tree that a target lowers into a driver command. It calls into the pipeline-stage cluster (hub `MongoStageNode`) 11 times, and that cluster calls back 15 times, since a `$match` stage holds a filter expression and a filter expression is assembled inside a stage. The whole `2-mongo-family` group repeats the `2-sql` layering, with its own foundation, authoring, tooling, query, transport, and runtime tiers."
    },
    {
      "name": "Postgres Target and DDL",
      "descriptionMarkdown": "545 symbols spanning the Postgres target, the postgres extension, and the SQL family's control adapter. `PostgresDdlNode`, `PostgresDdlVisitor`, `AlterTableAction`, and `quoteIdentifier` are the DDL side, the nodes a migration plan renders into `CREATE TABLE` and `ALTER TABLE`; `ExecuteRequestLowerer.lowerToExecuteRequest` lowers a statement into the shape the driver executes; and `postgresError` with `PostgresTargetErrorCode` shapes what surfaces when Postgres rejects it. The same three-way split (target, adapter, driver) repeats under [`packages/3-targets/`](https://github.com/prisma/prisma/tree/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-targets) for SQLite, and `Database Query Utilities` (315 symbols, hub `sqliteError`) is its SQLite twin, calling into this cluster 12 times."
    },
    {
      "name": "CLI Errors and Command Actions",
      "descriptionMarkdown": "649 symbols across [`packages/1-framework/1-core/errors/`](https://github.com/prisma/prisma/tree/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/1-framework/1-core/errors) and the CLI that consumes it. `CliStructuredError.is` and `CliStructuredError.code` classify a caught error, `normalizeError` puts anything thrown into that shape, and `ActionableCliError` with `ActionableCliError.nextActions` carries the remediation steps `chooseAction` and `runCommandAction` print. Its heaviest edge, 12 calls into `Migration Tools`, is the CLI invoking the migration engine; `Migration Tools` calls back 5 times to raise its own errors through the same reporting path."
    },
    {
      "name": "Also on the map",
      "descriptionMarkdown": "Two more of the ten drawn modules are CLI-side. `Migration Tools` (401 symbols, hub `MigrationToolsError`) lives in [`packages/1-framework/3-tooling/migration/`](https://github.com/prisma/prisma/tree/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/1-framework/3-tooling/migration) and assembles contract spaces: `createAggregateContractSpace`, `makeAggregateContractSpace`, and `createContractSpaceAggregate` combine the per-package contracts of a workspace into the single view a migration plans against. `CLI Migration Output Rendering` (398, hub `toneSpans`) is everything the terminal shows while that runs: `toneSpans` and `toneDrawing` parse the CLI's inline tone markup, `ClassifiedEdge` and the renderers under [`src/utils/formatters/`](https://github.com/prisma/prisma/tree/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/1-framework/3-tooling/cli/src/utils/formatters) draw the migration graph, and `shortDisplayHash` abbreviates a contract hash for display."
    }
  ],
  "startReading": {
    "symbols": [
      {
        "name": "AnyExpression",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/4-lanes/relational-core/src/ast/types.ts#L2237-L2259"
      },
      {
        "name": "SqlStorage",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/1-core/contract/src/ir/sql-storage.ts#L148-L166"
      },
      {
        "name": "CliStructuredError.is",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/1-framework/1-core/errors/src/control.ts#L117-L127"
      },
      {
        "name": "SyntaxNode.children",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/1-framework/2-authoring/psl-parser/src/syntax/red.ts#L213-L221"
      },
      {
        "name": "postgresError",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/postgres/src/errors.ts#L12-L18"
      },
      {
        "name": "MongoAggExpr",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-mongo-family/4-query/query-ast/src/aggregation-expressions.ts#L472-L483"
      },
      {
        "name": "defineNonEnumerable",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/1-core/schema-ir/src/ir/sql-schema-ir-node.ts#L76-L88"
      },
      {
        "name": "Collection",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client/src/collection.ts#L2595-L2601"
      },
      {
        "name": "MigrationToolsError",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/1-framework/3-tooling/migration/src/errors.ts#L39-L68"
      },
      {
        "name": "toneSpans",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/1-framework/3-tooling/cli/src/utils/formatters/tone-markup.ts#L88-L110"
      },
      {
        "name": "ColumnRef.of",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/4-lanes/relational-core/src/ast/types.ts#L509-L511"
      },
      {
        "name": "serializeValue",
        "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/1-framework/3-tooling/emitter/src/domain-type-generation.ts#L20-L48"
      }
    ],
    "endpoints": []
  },
  "requestFlow": [
    {
      "position": 1,
      "symbol": "CollectionImpl.all",
      "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client/src/collection.ts#L1025-L1027",
      "markdown": "`CollectionImpl.all` ([`packages/3-extensions/sql-orm-client/src/collection.ts#L1025`](https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client/src/collection.ts#L1025-L1027)) is the read terminal. It takes an optional `configure` callback for typed annotations, folds them into the collection's state, and calls the private dispatch."
    },
    {
      "position": 2,
      "symbol": "CollectionImpl.#dispatch",
      "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client/src/collection.ts#L2492-L2501",
      "markdown": "`CollectionImpl.#dispatch` ([`packages/3-extensions/sql-orm-client/src/collection.ts#L2492`](https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client/src/collection.ts#L2492-L2501)) packs the accumulated builder state into one options object: the execution context, the runtime, the collection state, and the table, model, and namespace names."
    },
    {
      "position": 3,
      "symbol": "dispatchCollectionRows",
      "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client/src/collection-dispatch.ts#L75-L109",
      "markdown": "`dispatchCollectionRows` ([`packages/3-extensions/sql-orm-client/src/collection-dispatch.ts#L75`](https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client/src/collection-dispatch.ts#L75-L109)) branches on whether the query has includes. With none, it compiles and runs one select; with includes, `dispatchWithIncludes` lowers every include descriptor into correlated subqueries so the read path still issues a single query."
    },
    {
      "position": 4,
      "symbol": "compileSelect",
      "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client/src/query-plan-select.ts#L1451-L1506",
      "markdown": "`compileSelect` ([`packages/3-extensions/sql-orm-client/src/query-plan-select.ts#L1451`](https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client/src/query-plan-select.ts#L1451-L1506)) turns that state into a plan. It resolves polymorphism against the contract, builds the projection and any table-inheritance joins, assembles a `SelectAst`, and derives the parameter list from the `ParamRef` nodes inside it."
    },
    {
      "position": 5,
      "symbol": "queryPlanRows",
      "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client/src/query-plan-rows.ts#L5-L10",
      "markdown": "`queryPlanRows` ([`packages/3-extensions/sql-orm-client/src/query-plan-rows.ts#L5`](https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-extensions/sql-orm-client/src/query-plan-rows.ts#L5-L10)) is a six-line seam: it hands the plan to `scope.query(plan)`, where `scope` is a `RuntimeScope`, the two-method interface `sql-relational-core` owns so the ORM client and the runtime share one contract without a layering inversion."
    },
    {
      "position": 6,
      "symbol": "SqlRuntimeBase.query",
      "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/5-runtime/src/sql-runtime.ts#L309-L314",
      "markdown": "`SqlRuntimeBase.query` ([`packages/2-sql/5-runtime/src/sql-runtime.ts#L309`](https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/5-runtime/src/sql-runtime.ts#L309-L314)) is the implementation behind that interface. It forwards to `queryAgainstQueryable`, which opens an async generator, prepares the plan, and streams decoded rows back."
    },
    {
      "position": 7,
      "symbol": "SqlRuntimeBase.lowerToDraft",
      "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/5-runtime/src/sql-runtime.ts#L254-L256",
      "markdown": "`SqlRuntimeBase.lowerToDraft` ([`packages/2-sql/5-runtime/src/sql-runtime.ts#L254`](https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/5-runtime/src/sql-runtime.ts#L254-L256)) runs inside that preparation. It produces a draft with SQL rendered and params filled from the user-domain values the lowering collected from `ParamRef` nodes. No codec encoding has happened yet, which is the window where a middleware can still mutate those params through the `SqlParamRefMutator`."
    },
    {
      "position": 8,
      "symbol": "lowerSqlPlan",
      "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/5-runtime/src/lower-sql-plan.ts#L16-L41",
      "markdown": "`lowerSqlPlan` ([`packages/2-sql/5-runtime/src/lower-sql-plan.ts#L16`](https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/2-sql/5-runtime/src/lower-sql-plan.ts#L16-L41)) calls `adapter.lower(ast, { contract, params })`, unwraps the returned literal slots into a bare value array, and freezes the result. A bind-site slot arriving here means the caller sent a prepared-statement AST down the ad-hoc path, and it raises `RUNTIME.PREPARE_BIND_ON_ADHOC`."
    },
    {
      "position": 9,
      "symbol": "PostgresAdapterImpl.lower",
      "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-targets/6-adapters/postgres/src/core/adapter.ts#L85-L97",
      "markdown": "`PostgresAdapterImpl.lower` ([`packages/3-targets/6-adapters/postgres/src/core/adapter.ts#L85`](https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-targets/6-adapters/postgres/src/core/adapter.ts#L85-L97)) is the concrete adapter behind that interface call. It refuses DDL, which belongs to the control adapter, and delegates the rest with its codec registry attached."
    },
    {
      "position": 10,
      "symbol": "renderLoweredSql",
      "sourceUrl": "https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-targets/6-adapters/postgres/src/core/sql-renderer.ts#L151-L155",
      "markdown": "`renderLoweredSql` ([`packages/3-targets/6-adapters/postgres/src/core/sql-renderer.ts#L151`](https://github.com/prisma/prisma/blob/dd6c12bfab432998a75e4cdcf8df45d65648e3d5/packages/3-targets/6-adapters/postgres/src/core/sql-renderer.ts#L151-L155)) walks the AST and emits Postgres-flavoured `{ sql, params }`. It collects the ordered `ParamRef` nodes first, assigns each a `$n` index, then renders. The runtime and control entry points share this one function so an emitted migration and a live query produce byte-identical SQL for the same AST."
    }
  ],
  "diagrams": [
    {
      "url": "https://symvanta.com/architecture/prisma/module-map.svg",
      "encodingFormat": "image/svg+xml"
    }
  ]
}
