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

postgraphile

v5.0.0

Published

Automatic, high performance, and highly customizable GraphQL API for PostgreSQL

Readme

PostGraphile

High-performance GraphQL APIs, honed exactly to your needs, with minimal effort expended

GitHub Sponsors Discord chat room Follow Follow

Documentation: https://postgraphile.org/postgraphile/next/

About

Focus on only writing the code that brings value.

If you use Postgres as your primary datastore, PostGraphile helps you build best-practices, well-structured, frontend-focused, and high-performance GraphQL APIs, honed exactly to your needs, with minimal effort expended.

How it works

Rather than spending months hand-writing and maintaining an entire schema, PostGraphile handles the repetitive parts so you can focus on the code that really matters.

Out of the box, PostGraphile analyzes your PostgreSQL database and builds a complete, consistent GraphQL schema informed by its tables, relations, functions, indexes, permissions, and your configuration. Into this living baseline that evolves with your database, you seamlessly compose customizations and extensions to sculpt the perfect GraphQL API for your client's needs with minimal effort:

  • Seamlessly extend the schema with your own custom types and fields that can execute SQL or Node.js code (see "Extensible" below).
  • Use database permissions to govern which parts to expose; it's quick, ergonomic, granular, and it improves your security posture.
  • Use our powerful plugin and preset system to apply your general preferences to the generated GraphQL schema.
  • Use simple "tags" to fine-tune individual database entities: renaming them, choosing when/how to expose them, changing their type/presentation/nullability, indicating abstract types (interfaces/unions), introducing additional relations, and more.
  • Use our "inflection" system to overhaul naming across the generated schema (we recommend @graphile/simplify-inflection if your database schema meets the requirements).
  • Use third party plugins to add new features and capabilities.
  • And much more!

Execution efficiency

Backed by the cutting edge Grafast planning and execution engine for GraphQL, PostGraphile has outstanding performance, typically out-performing hand-written GraphQL schemas using traditional GraphQL.js resolvers.

Consistency

PostGraphile's autogeneration of the common parts of your API helps ensure consistency, whilst its plugin and preset system allows you to tweak every facet of your schema to your heart's content.

No lock-in

If you ever feel the need to leave PostGraphile, you can export your schema as executable code, and take over maintenance yourself — all without losing the performance advantages of our fully-planned execution.

Extensible

GraphQL is frontend-focused, so in most cases your API should be shaped by client needs rather than being a simple 1-to-1 map of your database. PostGraphile helps you achieve this with minimal effort.

Many of your business domain objects will naturally align across the frontend, backend, and database; for these, a few tags or helper functions are typically sufficient to accommodate minor differences.

For domains that don't fit that model, PostGraphile is built with extensibility and composability at its heart. You can seamlessly adjust the schema to fit, without sacrificing the productivity and performance gains you get from the rest of the system.

Almost every feature in PostGraphile, from introspection through to type generation and on to adding pagination arguments, is implemented via plugins. PostGraphile's plugin API is incredibly powerful and flexible; it's designed for you to use and even has helper factories to give more ergonomic APIs for common needs.

Let's take the example of a checkout process. Your database only exposes the underlying products, prices, cart_items, and so on, but your frontend needs to know subtotal, tax, etc. Prices may vary depending on promotional discounts or other business rules. It should not be up to the client to implement these details client-side, instead your GraphQL schema should expose them as helpful strongly typed and well documented fields.

In PostGraphile, you can handle this in the database:

-- Hide the "prices" table from the GraphQL schema.
comment on table prices is '@behavior -*';

-- Create the `Product.unitPrice` field to get the current price of an item
create function products_unit_price(p products) returns money as $$
  select unit_price
  from prices
  where product_id = p.product_id
  and now() >= valid_from
  and now() < valid_until;
$$ language sql stable;

-- Add documentation for this field
comment on function products_unit_price is
  'The unit price at the current time, reflecting promotional discounts.';

This will automatically add a Product.unitPrice field that finds the current unit price of the given product according to the time validity. (Here we assume the time periods will not overlap, but if they do then you can add order by unit_price asc limit 1 to the query.)

If your business logic is more complex, you could instead achieve this via a schema extension; this also allows for more advanced logic such as querying an external service to determine shipping costs.

Let's imagine we didn't add the above database function, and instead want to implement the logic in TypeScript, along with adding cart "summary" logic (subtotal, shipping, tax, total).

import { extendSchema } from "postgraphile/utils";
import { constant, context, get } from "postgraphile/grafast";
import { batchSummarizeCart } from "./businessLogic/cart";

export default extendSchema((build) => {
  const {
    pgExecutor,
    pgResources: { cartItems, products, prices },
  } = build;
  return {
    typeDefs: /* GraphQL */ `
      extend type Product {
        "The unit price at the current time, reflecting promotional discounts."
        unitPrice: Money!
      }

      extend type Cart {
        summary: CartSummary
      }

      type CartSummary {
        subtotal: Money!
        shipping: Money!
        tax: Money!
        total: Money!
      }
    `,
    plans: {
      Product: {
        unitPrice($item) {
          // Find the relevant price
          const productId = $item.get("product_id");
          const $prices = prices.find({ productId: $productId });
          $prices.where(sql`now() >= valid_from and now() < valid_until`);

          // There's exactly one row, fetch it and return the unit price
          return $prices.single().get("unit_price");
        },
      },
      Cart: {
        summary($cart) {
          const $cartId = $cart.get("id");
          return loadOne($cartId, batchSummarizeCart);
        },
      },
      // CartSummary doesn't need plan resolvers, it can use the defaults.
    },
  };
});

With extendSchema() you can add custom types and fields that invoke arbitrary Node.js business logic, integrating with any datasource Node.js can communicate with. This can also be used to maintain backwards compatibility if and when you make breaking changes to your database schema. And that's just one of our plugin helpers, there's so much more you can do to make the schema your own!

Your business logic can be implemented in any way that you want and can do anything Node.js can do; typically we assume you're using DataLoader-style callbacks (you can actually use your DataLoader callbacks with loadOne/loadMany directly!) to enable batched loading, but the loadOne() and loadMany() steps you'd use to call them can have many advantages over DataLoader.

// businessLogic/cart.ts

import { context } from "postgraphile/grafast";

export const batchSummarizeCart = {
  // Plan to get access to the GraphQL context in our loader
  shared: () => context(),

  // `cartIds` is the batch of Cart identifiers, `shared` is the runtime GraphQL
  // context (shared by everything in the batch)
  async load(cartIds, { shared }) {
    const carts = await batchGetCartInfo(shared, cartIds);
    const cartsWithShipping = await batchCalculateShippingCosts(carts);
    const cartsWithTax = await batchCalculateTax(cartsWithShipping);
    return cartIds.map((cartId) => {
      const cartInfo = cartsWithTax.find((c) => c.cart_id === cartId);
      const { subtotal, shipping, tax } = cartInfo;
      const total = subtotal + shipping + tax;
      return { subtotal, shipping, tax, total };
    });
  },
};

/** Cart info from the database */
interface CartInfo {
  cart_id: number;
  shipping_address: Address;
  subtotal: number;
  mass: number;
}
async function batchGetCartInfo(shared, cartIds) {
  // Single DB fetch across all carts; you could use you ORM instead if you want.
  const result = await shared.withPgClient(shared.pgSettings, (db) =>
    db.query<CartInfo>({
      text: `
        select
          carts.id as cart_id,
          to_json(carts.shipping_address) as shipping_address,
          sum(cart_items.quantity * prices.unit_amount) as subtotal,
          sum(cart_items.quantity * products.mass) as mass
        from carts
        inner join cart_items
        on (cart_items.cart_id = carts.id)
        inner join prices
        on (
          prices.product_id = cart_items.product_id
          and now() >= valid_from
          and now() < valid_to
        )
        where carts.id = any($1::int[])
        group by carts.id
      `,
      values: [cartIds],
    }),
  );
  return result.rows;
}

interface CartInfoWithShipping extends CartInfo {
  shipping: number;
}

async function batchCalculateShippingCosts(carts: CartInfo[]) {
  // TODO: given the mass and address for each cart, determine its shipping cost
  return carts.map((cart) => ({ ...cart, shipping: 500 }));
}

interface CartInfoWithShippingAndTax extends CartInfoWithShipping {
  shipping: number;
}
async function batchCalculateTax(carts: CartInfoWithShipping[]) {
  // TODO: update with the correct taxes for the region
  const TAX_PERCENTAGE = 20;
  return carts.map((cart) => ({
    ...cart,
    tax: ((cart.subtotal + cart.shipping) * TAX_PERCENTAGE) / 100,
  }));
}

Summary

If your backend uses PostgreSQL as its primary datastore, and you use a conventional relational schema, PostGraphile is the best way to get your project up and running in record time; and, thanks to its incredibly efficient execution that eliminates under- and over-fetching on the backend, it helps you reach significant scale with minimal resources and minimal complexity.

Stop building boilerplate, iterate faster, and start shipping today with PostGraphile; click here to get started.

Crowd-funded open-source software

To help us develop this software sustainably, we ask all individuals and businesses that use it to help support its ongoing maintenance and development via sponsorship.

Click here to find out more about sponsors and sponsorship.

And please give some love to our featured sponsors 🤩:

* Sponsors the entire Graphile suite