PJPalJS

@paljs/plugins

Introduction

GraphQL plugins for Prisma that provide automatic field selection optimization. The main export, PrismaSelect, analyzes GraphQL queries and generates optimized Prisma select/include objects — only fetching the fields actually requested.

Installation

Peer Dependencies

  • @prisma/client ^6 or ^7
  • graphql ^15 || ^16

PrismaSelect

Basic Usage

typescript
import { PrismaSelect } from '@paljs/plugins';
 
// In your GraphQL resolver
const resolvers = {
  Query: {
    users: async (parent, args, context, info) => {
      const select = new PrismaSelect(info).value;
      return context.prisma.user.findMany({
        ...args,
        ...select,
      });
    },
  },
};

Typed Usage (v9)

With @paljs/generator, you get a ModelsObject type that eliminates any:

typescript
import { PrismaSelect } from '@paljs/plugins';
import type { ModelsObject } from './generated/paljs/types';
 
const select = new PrismaSelect<'User', ModelsObject>(info);
const users = await prisma.user.findMany(select.value);
// users is properly typed!

With Default Fields

Always include specific fields regardless of the GraphQL query:

typescript
const select = new PrismaSelect(info, {
  defaultFields: {
    User: { id: true, email: true },
    Post: { id: true, title: true },
  },
}).value;

With Field Exclusion

Prevent sensitive fields from being selected:

typescript
const select = new PrismaSelect(info, {
  excludeFields: {
    User: ['password', 'hash', 'salt'],
  },
}).value;

Function-Based Configuration

Dynamic defaults and exclusions based on the current selection:

typescript
const select = new PrismaSelect(info, {
  defaultFields: {
    Profile: (select) => {
      const base = { id: true };
      if (select.user) return { ...base, userId: true };
      return base;
    },
  },
  excludeFields: {
    User: (select) => {
      const excluded = ['password'];
      if (!select.user) excluded.push('email');
      return excluded;
    },
  },
}).value;

Prisma 7 — DMMF Changes

In Prisma 7, Prisma.dmmf is no longer exported. PrismaSelect uses DMMF for field validation (filtering invalid fields before they reach Prisma).

Without DMMF: PrismaSelect still works — it generates select objects but skips field validation. Invalid fields may cause Prisma runtime errors.

With generated DMMF (recommended):

typescript
import dmmf from './generated/paljs/dmmf';
 
const select = new PrismaSelect(info, {
  dmmf: [dmmf],
  defaultFields: { User: { id: true } },
}).value;

This is the recommended approach for Prisma 7. The @paljs/generator captures DMMF during prisma generate and outputs it as a JSON file.

sdlInputs

Generates SDL input type definitions from Prisma DMMF. Useful for SDL-first GraphQL servers:

typescript
import { sdlInputs } from '@paljs/plugins';
import dmmf from './generated/paljs/dmmf';
 
const inputTypeDefs = sdlInputs(dmmf);
 
const typeDefs = gql`
  ${inputTypeDefs}
 
  type Query {
    users(where: UserWhereInput): [User!]!
  }
`;

Performance

Without PrismaSelect

typescript
// Fetches ALL fields and ALL relations
const users = await prisma.user.findMany({
  include: {
    posts: { include: { comments: { include: { author: true } } } },
    profile: true,
  },
});

With PrismaSelect

typescript
// Only fetches fields requested in the GraphQL query
const select = new PrismaSelect(info).value;
const users = await prisma.user.findMany(select);
 
// For query: { users { id email posts { title } } }
// Generates: { select: { id: true, email: true, posts: { select: { title: true } } } }

Framework Examples

Apollo Server

typescript
import { ApolloServer } from '@apollo/server';
import { PrismaSelect } from '@paljs/plugins';
 
const resolvers = {
  Query: {
    users: (_, args, { prisma }, info) => {
      const select = new PrismaSelect(info).value;
      return prisma.user.findMany({ ...args, ...select });
    },
  },
};

GraphQL Yoga

typescript
import { createYoga, createSchema } from 'graphql-yoga';
import { PrismaSelect } from '@paljs/plugins';
 
const yoga = createYoga({
  schema: createSchema({
    resolvers: {
      Query: {
        users: (_, args, { prisma }, info) => {
          const select = new PrismaSelect(info).value;
          return prisma.user.findMany({ ...args, ...select });
        },
      },
    },
  }),
});

Command Palette

Search for a command to run...