<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Benjie</title>
    <description>The latest articles on DEV Community by Benjie (@benjie).</description>
    <link>https://dev.to/benjie</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F167783%2F66294871-4a69-49f2-9f11-b13d9f53f09f.png</url>
      <title>DEV Community: Benjie</title>
      <link>https://dev.to/benjie</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/benjie"/>
    <language>en</language>
    <item>
      <title>Major Grafast Beta: three down, one to go!</title>
      <dc:creator>Benjie</dc:creator>
      <pubDate>Mon, 14 Apr 2025 11:12:51 +0000</pubDate>
      <link>https://dev.to/graphile/major-grafast-beta-three-down-one-to-go-1lj</link>
      <guid>https://dev.to/graphile/major-grafast-beta-three-down-one-to-go-1lj</guid>
      <description>&lt;p&gt;In the first Gra&lt;em&gt;fast&lt;/em&gt; Working Group, we outlined 4 &lt;em&gt;major&lt;/em&gt; issues in Gra&lt;em&gt;fast&lt;/em&gt; that needed to be addressed before we could think about general release. With this release, 3 of these are now complete!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅⤵️ Global dependencies - solved via "unary" steps&lt;/li&gt;
&lt;li&gt;✅⤵️ Early exit - solved via "flags"&lt;/li&gt;
&lt;li&gt;✅🎉 &lt;strong&gt;Eradicating eval - this release!&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🤔🔜 Polymorphism&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’re proud to announce that the third of these, eradicating eval, is now addressed with the launch of &lt;code&gt;grafast@0.1.1-beta.21&lt;/code&gt;, and the approach has been fully adopted and tested via incorporation into &lt;code&gt;postgraphile@5.0.0-beta.40&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Input evaluation moved to runtime
&lt;/h2&gt;

&lt;p&gt;Since the beginning, Gra&lt;em&gt;fast&lt;/em&gt; has had the ability to add plan resolvers not just to fields, not just to arguments, but also to input object fields (including those within lists). This made Gra&lt;em&gt;fast&lt;/em&gt;’s planning really ergonomic for things like nested filters. But it turns out it’s really problematic for certain shapes of input — planning would put constraints on the variables compatible with the plan, requiring potentially unlimited numbers of operation plans needing to be built for the same GraphQL document. Worse: for large input trees involving lists, the number of steps generated could be overwhelming, resulting in the deduplication phase taking excessive time.&lt;/p&gt;

&lt;p&gt;One particular user example that could cause 4 minutes of planning time from just a 100kB input made it clear that we had overreached with using plan resolvers too deep into inputs; so we’ve scaled it back so that you can only add plan resolvers to fields and arguments, you can no longer attach &lt;code&gt;applyPlan&lt;/code&gt; or &lt;code&gt;inputPlan&lt;/code&gt; to input object fields. This was something that we used a lot in PostGraphile and its various plugins, but very few people (no-one?) used externally so it was ripe for removal.&lt;/p&gt;

&lt;p&gt;That problematic query that took 4 minutes to plan before? It now takes 1.1ms to plan, yielding a 200,000x speedup!&lt;/p&gt;

&lt;h3&gt;
  
  
  What does this mean for my codebase?
&lt;/h3&gt;

&lt;p&gt;Hopefully good things! Please update to the latest &lt;code&gt;grafast@beta&lt;/code&gt; and for most users everything should work as before, only better.&lt;/p&gt;

&lt;p&gt;I’ve outlined some of the most common changes you may need to make below, but if you are impacted by any other changes, please ask for help &lt;a href="https://discord.gg/graphile" rel="noopener noreferrer"&gt;in the chat&lt;/a&gt; — AFAIK most of the other things that have had significant changes are used by almost no-one except me, so it doesn’t make sense for me to invest time documenting it here since the software is still in beta. If you’re curious, many items are documented in both the changelogs and the pull requests where the changes occurred.&lt;/p&gt;

&lt;h4&gt;
  
  
  Change &lt;code&gt;fieldArgs.get&lt;/code&gt; to &lt;code&gt;fieldArgs.getRaw&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Because we’ve removed &lt;code&gt;inputPlan&lt;/code&gt;, the &lt;code&gt;fieldArgs.get(key)&lt;/code&gt; method is no more; instead use &lt;code&gt;fieldArgs.getRaw(key)&lt;/code&gt; which is equivalent unless the inputs had plans (which they cannot any more). You'd know if you had plans on your inputs, it's very unlikely you did if you were writing your own Gra&lt;em&gt;fast&lt;/em&gt; schema.&lt;/p&gt;

&lt;h4&gt;
  
  
  Converting &lt;code&gt;applyPlan&lt;/code&gt; and &lt;code&gt;inputPlan&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;If your input object fields did have plan resolvers then instead of having Gra&lt;em&gt;fast&lt;/em&gt; automatically call them on each and every input field recursively at plan-time, we now have the &lt;code&gt;applyInput&lt;/code&gt; and &lt;code&gt;bakedInput&lt;/code&gt; steps that represent runtime application or transform of these inputs recursively via a single step in our plan diagram.&lt;/p&gt;

&lt;p&gt;We’ve managed to make this new runtime system very similar in shape to the old plan-time system (largely enabled by how closely we managed to get the Gra&lt;em&gt;fast&lt;/em&gt; plan syntax to the syntax of code you would normally write at runtime), so if you do need to transform any it shouldn't take much effort. The first change is to rename &lt;code&gt;applyPlan&lt;/code&gt; to &lt;code&gt;apply&lt;/code&gt;, and &lt;code&gt;inputPlan&lt;/code&gt; to &lt;code&gt;baked&lt;/code&gt;. From there, your code might just work straight away, or it might need some more small tweaks (e.g. &lt;code&gt;fieldArgs&lt;/code&gt; is no longer present, it’s been replaced with simply the runtime value of the current field).&lt;/p&gt;

&lt;h4&gt;
  
  
  No more &lt;code&gt;$step.eval*()&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;The eval methods are now marked as internal so you will get TypeScript errors if you try and use them. They will likely be removed at some point after release, so you should be sure to migrate away from using them at your earliest opportunity. But you weren’t using them anyway… right?&lt;/p&gt;

&lt;p&gt;If you were, a new &lt;code&gt;.apply()&lt;/code&gt; pattern has been added to various steps to enable you to specify runtime tweaks the step can apply as its executing, for example changing the &lt;code&gt;ORDER BY&lt;/code&gt; clause in an SQL query based on a variable argument. You may want to adopt a similar pattern in your own step classes.&lt;/p&gt;

&lt;h4&gt;
  
  
  ExecutableStep renamed to Step
&lt;/h4&gt;

&lt;p&gt;This one is more cosmetic…&lt;/p&gt;

&lt;p&gt;Since we no longer have plan resolvers deep in inputs, we no longer have the &lt;code&gt;ModifierStep&lt;/code&gt; system that was used for managing them (it’s been replaced with &lt;code&gt;Modifier&lt;/code&gt; which happens at runtime). Since we no longer have ModifierStep, we no longer need &lt;code&gt;BaseStep&lt;/code&gt; to be separate from and inherited by &lt;code&gt;ExecutableStep&lt;/code&gt;, so we’ve merged them. Since this is the base class for &lt;em&gt;all&lt;/em&gt; steps now, we’ve renamed it to simply &lt;code&gt;Step&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We have kept an &lt;code&gt;ExecutableStep&lt;/code&gt; export for backwards compatibility.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PostGraphile changes
&lt;/h2&gt;

&lt;p&gt;In addition to the changes above that impact everything that uses Gra&lt;em&gt;fast&lt;/em&gt;, here are some of the changes that specifically impact PostGraphile users.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQL generation moved to runtime
&lt;/h3&gt;

&lt;p&gt;PostGraphile's various SQL-running steps like PgSelectStep now build their queries at runtime rather than plantime. They use the "builder" pattern, where much of the SQL query can be established at plan-time, but final tweaks can be applied at run-time (register tweaks via the &lt;code&gt;$pgSelect.apply($callback)&lt;/code&gt; method) before the query is built.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQL efficiency increased
&lt;/h3&gt;

&lt;p&gt;Since we have more information at run-time, our SQL queries were able to become even simpler, 10% smaller on average across our test suite! This nets us a modest performance improvement inside PostgreSQL, but the shift to runtime does cost us a little performance in the JS layer since queries now need to be built for every request, rather than once per plan. We're happy with this tradeoff; one of the core goals of PostGraphile V5 (and the motivation for Grafast in the first place) was to shift load from the PostgreSQL layer (which is non-trivial to scale) to the Node.js layer (which is easy to scale horizontally).&lt;/p&gt;

&lt;h3&gt;
  
  
  Postgres Arrays now parse 5x faster
&lt;/h3&gt;

&lt;p&gt;I've also &lt;a href="https://github.com/bendrucker/postgres-array/pull/19" rel="noopener noreferrer"&gt;backported&lt;/a&gt; these &lt;a href="https://github.com/bendrucker/postgres-array/pull/20" rel="noopener noreferrer"&gt;fixes&lt;/a&gt; into the &lt;code&gt;postgres-array&lt;/code&gt; npm module for everyone that uses &lt;code&gt;pg&lt;/code&gt; to benefit from.&lt;/p&gt;

&lt;h3&gt;
  
  
  Easier to write SQL fragments
&lt;/h3&gt;

&lt;p&gt;Added a new feature to &lt;code&gt;pg-sql2&lt;/code&gt; that allows us to handle non-SQL parameter embeds with custom code, making it easier to write custom SQL, e.g. if a value is already coming from SQL you can embed it directly without having to invoke placeholder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; const $fooId = $foo.get('id');
&lt;span class="gd"&gt;-$pgSelect.where(sql`foo_id = ${$pgSelect.placeholder($fooId)}`);
&lt;/span&gt;&lt;span class="gi"&gt;+$pgSelect.where(sql`foo_id = ${$fooId}`);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've also added the ability to embed dynamic SQL fragments that can be dependent on runtime values (these values must be unary, i.e. they must come from GraphQL field arguments or derivatives thereof):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$includeArchived&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fieldArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRaw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;includeArchived&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$includeArchived&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;includeArchived&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;includeArchived&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`is_archived is false`&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;$pgSelect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$condition&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Additional changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  makeGrafastSchema
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🚨The structure of &lt;code&gt;makeGrafastSchema&lt;/code&gt; as it relates to arguments and input object fields has changed a little; use TypeScript to guide you. I'm hoping this is the last change of its kind before release.&lt;/li&gt;
&lt;li&gt;New shortcuts added for argument &lt;code&gt;applyPlan()&lt;/code&gt; and input field &lt;code&gt;apply()&lt;/code&gt; methods.&lt;/li&gt;
&lt;li&gt;Trimmed a load of unnecessary exported code, such as empty objects and field resolvers that do the same as the default field resolver.&lt;/li&gt;
&lt;li&gt;Fix bug in &lt;code&gt;makeGrafastSchema&lt;/code&gt; that fails to build schema sometimes if a field uses a function shortcut rather than object definition.&lt;/li&gt;
&lt;li&gt;Fix bug in &lt;code&gt;makeGrafastSchema&lt;/code&gt; that sometimes doesn't allow defining input objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚨 If you use &lt;code&gt;graphile-export&lt;/code&gt; to export your schema as executable code, be sure to regenerate your schemas as the old generated code could be misinterpreted by the new &lt;code&gt;makeGrafastSchema&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  graphile-export
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Massively improved the executable code output from &lt;code&gt;graphile-export&lt;/code&gt; in combination with the changes to &lt;code&gt;makeGrafastSchema&lt;/code&gt; above.&lt;/li&gt;
&lt;li&gt;PostGraphile's "kitchen sink" schema export code now outputs 37KLOC rather than 47KLOC - a significant reduction in complexity!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Improved plan diagrams
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Plan diagrams now reveal (via &lt;code&gt;@s&lt;/code&gt; text) if a step is meant to be streamed.&lt;/li&gt;
&lt;li&gt;Constant steps improved.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Object: null prototype&lt;/code&gt; simplified to &lt;code&gt;§&lt;/code&gt; in output.&lt;/li&gt;
&lt;li&gt;Hoist steps during &lt;code&gt;optimize&lt;/code&gt; phase.&lt;/li&gt;
&lt;li&gt;We no longer render dependencies on the &lt;code&gt;undefined&lt;/code&gt; constant, because it's messy and doesn't add value&lt;/li&gt;
&lt;li&gt;We group when there are multiple dependencies to the same step from the same step, and label the line with the count instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step classes
&lt;/h3&gt;

&lt;p&gt;When writing your own step classes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ExecutionValue&lt;/code&gt; has gained a new &lt;code&gt;.unaryValue()&lt;/code&gt; method that returns the unary value for unary execution values, and throws an error for non-unary execution values. This is much safer than the previous &lt;code&gt;.at(0)&lt;/code&gt; trick which did not assert that you were actually dealing with a unary execution value.&lt;/li&gt;
&lt;li&gt;If you were using &lt;code&gt;@stream&lt;/code&gt; (incremental delivery) and had written your own &lt;code&gt;Step&lt;/code&gt; class with stream support, first of all: amazing! Please let me know you did that (&lt;em&gt;via email or &lt;a href="https://discord.gg/graphile" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;&lt;/em&gt;)! Secondly, you'll need to either rename your &lt;code&gt;stream&lt;/code&gt; function to &lt;code&gt;execute&lt;/code&gt; or merge its code into your existing &lt;code&gt;execute&lt;/code&gt; method if you have one. It turns out there wasn't much point in separating them, and you can confer a lot of benefit from merging them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Other Gra&lt;em&gt;fast&lt;/em&gt; improvements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Compatible mutation operations can now complete synchronously via &lt;code&gt;grafastSync()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Fixes bug in input objects where keys that weren't set would still be present with value &lt;code&gt;undefined&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Fix bug in step caching relating to polymorphism&lt;/li&gt;
&lt;li&gt;New &lt;code&gt;items()&lt;/code&gt; conventional method for extracting the items from a collection (makes for easier compatibility with connections)&lt;/li&gt;
&lt;li&gt;Error handling improved&lt;/li&gt;
&lt;li&gt;Lists improved - especially error handling and deduplication logic; as well as allowing returning connection-capable steps in list positions&lt;/li&gt;
&lt;li&gt;Optimization to Gra&lt;em&gt;fast&lt;/em&gt;'s internal execution values, which are used heavily in hot paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Thank you Sponsors
&lt;/h3&gt;

&lt;p&gt;Gra&lt;em&gt;fast&lt;/em&gt; and PostGraphile are crowd-funded open-source software, they rely on crowd-sourced funding from individuals and companies to keep advancing.&lt;/p&gt;

&lt;p&gt;If your company benefits from Gra&lt;em&gt;fast&lt;/em&gt;, PostGraphile or the wider Graphile suite, you should consider asking them to fund our work. By significantly reducing the amount of work needed to achieve business goals and reducing running costs, Graphile's software results in huge time and money savings for users. We encourage companies to contribute a portion of these savings back, enabling the projects to advance more rapidly, and result in even greater&lt;br&gt;
savings for your company.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/sponsor/"&gt;Find out more about sponsorship here on our website&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>grafast</category>
      <category>release</category>
      <category>postgraphile</category>
    </item>
    <item>
      <title>Step Aside Resolvers — Grafast 0.1 Released!</title>
      <dc:creator>Benjie</dc:creator>
      <pubDate>Fri, 13 Oct 2023 13:07:20 +0000</pubDate>
      <link>https://dev.to/graphile/step-aside-resolvers-grafast-01-released-1gjn</link>
      <guid>https://dev.to/graphile/step-aside-resolvers-grafast-01-released-1gjn</guid>
      <description>&lt;p&gt;&lt;strong&gt;Grafast is finally here — a new holistic execution engine for GraphQL. It enables greater efficiency across the entire backend stack by leveraging the declarative nature of GraphQL to give your business logic a better understanding of everything it needs to do.&lt;/strong&gt; It‘s backwards compatible, so you can adopt it incrementally within your existing schema and it‘s finally ready to try with &lt;a href="https://www.npmjs.com/package/grafast" rel="noopener noreferrer"&gt;the &lt;code&gt;grafast&lt;/code&gt; module on npm&lt;/a&gt;; or check out &lt;a href="https://github.com/graphile/crystal/tree/main/grafast/grafast" rel="noopener noreferrer"&gt;the source code on GitHub&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4ao-zjiOGx8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
I launched Grafast v0.1 at GraphQL Conf, above is the full video of my talk which covers what Grafast is and how it can improve application performance, reduce operational costs, all without being a significant burden on developers.



&lt;h2&gt;
  
  
  Grafast Working Group
&lt;/h2&gt;

&lt;p&gt;There‘s still decisions to be made and edges to be smoothed before Grafast can become a specification that can be implemented in any language. If the potential of this technology is interesting to you, please &lt;a href="https://github.com/grafast/wg" rel="noopener noreferrer"&gt;join the Grafast working group&lt;/a&gt; and get involved. We all deserve our future of easy GraphQL execution efficiency!&lt;/p&gt;

&lt;p&gt;If you don‘t have time to watch the video above, here‘s a little about Grafast:&lt;/p&gt;

&lt;h2&gt;
  
  
  “GraphQL‘s execution model is wrong for most servers”
&lt;/h2&gt;

&lt;p&gt;GraphQL is a declarative language; the requests specify everything that the client is asking for up–front.&lt;/p&gt;

&lt;p&gt;But the resolver–based execution model &lt;strong&gt;&lt;em&gt;obfuscates&lt;/em&gt;&lt;/strong&gt; this knowledge — when implemented naively, resolvers can very quickly result in serious performance issues; and even when implemented well they leave a lot to be desired.&lt;/p&gt;

&lt;p&gt;DataLoader is one of the suggested approaches to solve the “N+1 Problem” but this is only the most egregious performance issue a GraphQL schema may face — there are plenty of related issues that can build up as your schemas and operations get more complex.&lt;/p&gt;

&lt;p&gt;I set out not only to solve the well–known N+1 problem and the more subtle under– and over–fetching problems, but to help you achieve the most efficient execution for your GraphQL schema no matter what data sources you‘re working with! The solution? Leverage the declarative nature of GraphQL via a new general purpose query planner.&lt;/p&gt;

&lt;h2&gt;
  
  
  “Step aside resolvers! There‘s a new way to execute GraphQL”
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuuzm8wh2jx2ps16n2cd6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuuzm8wh2jx2ps16n2cd6.png" alt="A flow diagram showing the stages of Grafast: Plan resolvers and the incoming GraphQL request are used to draft a plan, which is then optimized, finalized and executed, then the results are sent." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
Grafast calls “plan resolvers” to determine the requirements for each field in the GraphQL request, ultimately forming a draft “operation plan”. Once drafted, the plan is optimized and executed.



&lt;p&gt;Grafast has been designed from the ground up to give schema designers the tools they need to ensure their schemas are executing as efficiently as possible, whilst ensuring that writing their logic is still a pleasant experience. To achieve this, Grafast favours a planning strategy which takes a holistic approach to understanding the incoming operation and unlocks the potential for significant optimizations: optimizations that are not achievable with a resolver–based execution model unless one puts in herculean effort (and a little sorcery 😉).&lt;/p&gt;

&lt;p&gt;Grafast, like GraphQL, is not specific to any particular technology stack, business logic shape or data storage layer. It doesn‘t care if you‘re using relational databases, document stores, ORMs, HTTP APIs, file systems or &lt;em&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc1149" rel="noopener noreferrer"&gt;carrier pigeons&lt;/a&gt;&lt;/em&gt;. Any valid GraphQL schema can be implemented with Grafast, and a Grafast schema can query any data source, business logic or service.&lt;/p&gt;

&lt;p&gt;Though it supports traditional resolvers, Grafast encourages developers to use “plan resolvers”: small functions similar to resolvers but which describe the required data, rather than actually fetching it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fknpdu4hkrzhv53p9h5sj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fknpdu4hkrzhv53p9h5sj.png" alt="A comparison between a traditional resolver and a plan resolver. The plan resolver is about the same length and mirrors the shape of the traditional resolver, but the key difference is it describes how to get the data rather than actually fetching it." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

Plan resolvers are similar to traditional resolvers, they even follow the same shape, but the key difference is they describe HOW to get the data rather than actually fetch it themselves.




&lt;p&gt;Grafast takes the GraphQL request and, using the plan resolvers, drafts an execution plan which can be optimized and streamlined. The optimization may involve changing the shape of execution significantly from the shape the GraphQL request would imply, enabling the system to satisfy the requirements of the request in the most efficient manner.&lt;/p&gt;

&lt;p&gt;When the planning phase is complete, Grafast will execute this highly optimized execution plan, and feed the result into the output plan, which efficiently prepares the result to send to the GraphQL client.&lt;/p&gt;

&lt;p&gt;If another request comes in using the same GraphQL document but different variables, Grafast can reuse the plan and jump straight to the highly optimized execution phase.&lt;/p&gt;

&lt;p&gt;This greater understanding of the needs of the GraphQL requests unlocks entire new avenues for optimization, without sacrificing tried–and–trusted approaches such as caching. The result is greater efficiency — not just in your GraphQL server, but also in the backend services that it relies on — letting your team operate with a simpler architecture for much longer, allowing your engineers to focus on shipping better experiences for your customers rather than on the complexities of keeping a complicated architecture running smoothly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“&lt;strong&gt;Probably worth looking into the work &lt;a class="mentioned-user" href="https://dev.to/benjie"&gt;@benjie&lt;/a&gt; is doing with Grafast as well. Feels like the missing substrate in the GraphQL world.&lt;/strong&gt;”&lt;br&gt;
 -- Sean Grove &lt;a href="https://twitter.com/sgrove/status/1696572548803162477" rel="noopener noreferrer"&gt;August 29, 2023&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Grafast already works and some of my &lt;a href="https://graphile.org/sponsors" rel="noopener noreferrer"&gt;sponsors&lt;/a&gt; are already running it in production. You can try it out today by following the guide at &lt;a href="https://grafast.org" rel="noopener noreferrer"&gt;grafast.org&lt;/a&gt;. All that‘s left for me to say now is, if the potential of this new technology is interesting, then please:&lt;/p&gt;

&lt;h2&gt;
  
  
  Help shape the future on 24th October and join the &lt;a href="https://github.com/grafast/wg" rel="noopener noreferrer"&gt;Grafast working group&lt;/a&gt;!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fej9tj1exxcd8hb0u5r22.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fej9tj1exxcd8hb0u5r22.png" alt="A cartoon graphic of superheroes looking over their city at sunset. The text reads " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>grafast</category>
      <category>graphql</category>
      <category>opensource</category>
      <category>news</category>
    </item>
    <item>
      <title>PostGraphile V5 public beta — get involved!</title>
      <dc:creator>Benjie</dc:creator>
      <pubDate>Thu, 03 Aug 2023 14:59:16 +0000</pubDate>
      <link>https://dev.to/graphile/postgraphile-v5-public-beta-get-involved-1lg9</link>
      <guid>https://dev.to/graphile/postgraphile-v5-public-beta-get-involved-1lg9</guid>
      <description>&lt;h4&gt;
  
  
  It’s finally here! The day has come that you can get your hands on an &lt;em&gt;early release&lt;/em&gt; of PostGraphile Version 5; but we do have an ask: please help us to get it ready for release.
&lt;/h4&gt;

&lt;p&gt;We need help writing automated tests, validating it works in your real-world applications, improving the documentation, keeping up with issues and community support, porting plugins, smoothing edges, and as always we need financial support so we can keep investing our time into V5 and our other projects.&lt;/p&gt;

&lt;p&gt;It has taken us 3.5 years to get to this point and we’re pretty happy with the result, but there’s still plenty to be done before we’re ready to give it the big V5.0.0 stamp of approval!&lt;/p&gt;

&lt;h2&gt;
  
  
  How can I help?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Help us to ensure that the documentation is ready.&lt;/strong&gt; We’ve invested many weeks into writing the documentation for the various packages and projects (22 of them at last count!) which make up PostGraphile V5, but there’s still lots to do. We need people to read and follow the documentation, and to find the mistakes therein and submit issues or even patches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Help us to ensure that the software addresses your needs.&lt;/strong&gt; We’ve spent three years building this system, but it’s only really been tested by other people in the last 6 months. Early signs are very positive, but we want to know: does it work for you? Does it do what you need it to?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Help us to ensure that the transition from V4 is as easy as possible.&lt;/strong&gt; We’ve spent a significant amount of time making the transition from V4 to V5 as easy as we can, building a preset that generates an almost identical schema, porting some of the V4 plugins to V5, and writing &lt;a href="https://postgraphile.org/postgraphile/next/migrating-from-v4/" rel="noopener noreferrer"&gt;detailed migration documentation&lt;/a&gt;. But we need your help: did migrating from V4 work well for you? Where were the rough edges, and how can we smooth them? Are you willing to help port community V4 plugin to V5?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Help us to test V5.&lt;/strong&gt; We have ported the V4 test suite over to V5 so we know that it works well for that, but there’s so many different combinations of options and plugins that you can do with PostGraphile that many have only been tested manually, and they really need automated tests to prevent regressions. We also need you to use V5 in your own applications and let us know how you get on — both negative and positive — to help us move towards the all-important 5.0.0 release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Help us to improve the experience of V5.&lt;/strong&gt; We’ve put a lot of effort into both documentation and TypeScript types, but these can always be improved. There’s boilerplate in a few places that could be addressed with improvements to APIs, or with new abstractions. Try it out, and help us to improve the developer experience!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Help us to educate people about V5.&lt;/strong&gt; We don’t have a marketing department, we cannot afford a developer relations team or to sponsor big events. We’ll need your help to get the word out about PostGraphile V5, when the time comes; in the meantime we could really do with some help building example applications and tutorials to help people get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does “beta” mean for PostGraphile?
&lt;/h2&gt;

&lt;p&gt;We believe that &lt;strong&gt;PostGraphile V5 is suitable to run in production&lt;/strong&gt; and that we’ve completed most of the significant API rewrites that we wanted to make. There’s still some expected (and maybe a couple unexpected) changes to come, but mostly the beta phase is there to gather feedback from the community about how it works for you, and to leave space to make breaking changes if they turn out to be necessary before we place the stamp on the final V5.0.0 release.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tests, docs and examples
&lt;/h3&gt;

&lt;p&gt;Many of the &lt;a href="https://github.com/benjie/crystal/milestone/3" rel="noopener noreferrer"&gt;remaining issues&lt;/a&gt; are to add tests, write documentation and build examples; if you’re someone who doesn’t like to ask politely for help and expects the documentation to be complete when they come to use the software then you should probably hold off from using PostGraphile V5 until the v5.0.0 release is out.&lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript types
&lt;/h3&gt;

&lt;p&gt;One significant outstanding task which will likely cause some “breaking changes” is to review and potentially rewrite some of the TypeScript types. In some places types are a bit loose, in others there are old generics left around that are no longer needed, or generics in the wrong order, or other similar concerns. These issues don’t make the system unsafe to run in production, but they do require breaking changes to resolve, and we don’t want to have to jump to version 6 just to fix the TypeScript types of one of our APIs!&lt;/p&gt;

&lt;p&gt;We would love your help with this if you’re good at TypeScript!&lt;/p&gt;

&lt;h3&gt;
  
  
  Other “nice-to-haves”
&lt;/h3&gt;

&lt;p&gt;There are also a couple of other features that need to be added, for example integrating the Koa adaptor with Koa’s websocket framework like we've already done for Fastify. V4 of PostGraphile “emulated” an express stack for websocket connections in order to allow things like &lt;code&gt;pgSettings&lt;/code&gt; to continue to function, but in V5 we’ll be better integrating the functionality of the different webservers — you’ll be able to read about that in Part 7 of &lt;a href="https://dev.to/benjie/series/23459"&gt;our “Intro to V5” series&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;There’s also a bunch of optional enhancements that we’d really like to have in place before we launch v5.0.0 but if necessary we can do them later:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;digging into the generated SQL and optimizing it &lt;em&gt;even further&lt;/em&gt;,&lt;/li&gt;
&lt;li&gt;integrating the Node http2 webserver,&lt;/li&gt;
&lt;li&gt;optimizing the code that’s exported by the Graphile Export command &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-6-excellent-executable-exports-1150"&gt;you may have read about last week&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s also the ongoing work to improve the tooling around our tooling, to make it easier for you to debug issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I try it out?
&lt;/h2&gt;

&lt;p&gt;If you’re a V4 user then now is an excellent time to take V5 for a spin and let us know how you get on! You don’t even have to commit to migrating (though we hope once you’ve had a go you’ll definitely want to!), just some quick experiments with the things that you use PostGraphile for could be very useful.&lt;/p&gt;

&lt;p&gt;You can read all about the new features in V5 in our new series &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-1-replacing-the-foundations-3lh0"&gt;Intro to V5&lt;/a&gt; or if you prefer to just read the highlights, check out the migration guide’s &lt;a href="https://postgraphile.org/postgraphile/next/migrating-from-v4/v5-new-feature-summary" rel="noopener noreferrer"&gt;new feature summary&lt;/a&gt; and be sure to expand the bullets that have more details!&lt;/p&gt;

&lt;p&gt;All the packages are published under the &lt;code&gt;@beta&lt;/code&gt; tag, so you'll need to ensure you include that when issuing install instructions (e.g. &lt;code&gt;yarn add postgraphile@beta&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The fastest way to try PostGraphile V5 is with our new &lt;code&gt;pgl&lt;/code&gt; command which you don’t even have to install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx pgl@beta -P pgl/amber -e -c postgres:///my_db -s public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Replace the connection string and schema name with your database connection string and schema name(s).)&lt;/p&gt;

&lt;p&gt;If you want to try PostGraphile V5 with a few plugins, one option is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check out &lt;a href="https://github.com/benjie/ouch-my-finger" rel="noopener noreferrer"&gt;https://github.com/benjie/ouch-my-finger&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;yarn&lt;/code&gt; to install the dependencies&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;yarn postgraphile -c postgres:///my_db -s public&lt;/code&gt; giving your database’s connection string and schema(s)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ideally, you’d follow &lt;a href="https://postgraphile.org/postgraphile/next/migrating-from-v4/" rel="noopener noreferrer"&gt;the migration guide&lt;/a&gt; and start integrating V5 into your existing projects!&lt;/p&gt;

&lt;h3&gt;
  
  
  Join our testing community
&lt;/h3&gt;

&lt;p&gt;If you use Discord, join our server at &lt;a href="https://discord.gg/graphile" rel="noopener noreferrer"&gt;https://discord.gg/graphile&lt;/a&gt; and chat away with other V5 users — talk over the new features, discuss any issues you encounter and explore different ways of using the new projects. We look forward to welcoming you and hearing of your suggestions and successes with V5!&lt;/p&gt;

</description>
      <category>postgraphile</category>
      <category>graphql</category>
      <category>postgres</category>
      <category>beta</category>
    </item>
    <item>
      <title>Intro to PostGraphile V5 (Part 6): Excellent Executable Exports</title>
      <dc:creator>Benjie</dc:creator>
      <pubDate>Fri, 28 Jul 2023 10:57:20 +0000</pubDate>
      <link>https://dev.to/graphile/intro-to-postgraphile-v5-part-6-excellent-executable-exports-1150</link>
      <guid>https://dev.to/graphile/intro-to-postgraphile-v5-part-6-excellent-executable-exports-1150</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Benjie is the community–funded maintainer of the Graphile suite — a collection of MIT–licensed Node.js developer tooling for GraphQL and/or PostgreSQL. A key project in this suite is PostGraphile, a high performance, customizable and extensible GraphQL schema generator for APIs backed primarily (but not exclusively!) by PostgreSQL.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is part six in the "Intro to PostGraphile V5" series, which started with &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-1-replacing-the-foundations-3lh0"&gt;Part 1: Replacing the Foundations&lt;/a&gt;. This week, Benjie introduces another completely new feature coming in PostGraphile Version 5, available in pre–release now for all Graphile sponsors, find out more at &lt;a href="https://postgraphile.org/" rel="noopener noreferrer"&gt;postgraphile.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There was a time when barely a week would go by where someone didn't ask how to export their PostGraphile V4 schema so that they could run it in a different system, or merge it into another schema, or other such desires. PostGraphile V4 schemas are built on the fly, and their resolvers are built on the fly — they only exist in memory, not as real code. Furthermore, the resolvers are tied deeply into the lookahead system, which stores data into objects that are linked to (but not from) the GraphQL schema types. If you start trying to take a PostGraphile V4 schema apart and squeeze it into other things, everything quickly falls apart and it doesn't work, or at least doesn't work &lt;em&gt;right&lt;/em&gt;. This wasn't deliberate, it's just an artifact of the way the system was built, and of the capabilities of GraphQL.js at the time V4 was conceived.&lt;/p&gt;

&lt;p&gt;But since we're rebuilding the entire system from scratch, can we solve this problem? I think so!&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://www.npmjs.com/package/graphile-export/v/alpha" rel="noopener noreferrer"&gt;&lt;code&gt;graphile-export&lt;/code&gt;&lt;/a&gt; — an npm module that can be used to export executable code from an in–memory GraphQL schema in Node.js. Of course, to do this the code needs to be built in a particular way, and to help you do that I've built &lt;code&gt;eslint-plugin-graphile-export&lt;/code&gt;, an ESLint plugin based significantly on the React hooks ESLint plugin. This allows you to wrap code for resolvers, plan resolvers, isTypeOf and other callbacks in an &lt;code&gt;EXPORTABLE()&lt;/code&gt; call (a little like React's &lt;code&gt;useCallback()&lt;/code&gt; call) and the system will automatically determine the variables that each function is using from the parent scope so that they can be exported along with the function body (which is extracted via the magic of &lt;code&gt;func.toString()&lt;/code&gt; 😁).&lt;/p&gt;

&lt;p&gt;Importantly, this exported schema (which can be exported as a JavaScript file either using pure GraphQL.js class constructors for optimal performance, or more readably as a traditional typeDefs/resolvers–style object with plans instead of resolvers) does not depend on &lt;code&gt;graphile-build&lt;/code&gt;, &lt;code&gt;graphile-build-pg&lt;/code&gt; or any other tooling used purely during the schemas construction — it only contains dependencies on its runtime needs, typically &lt;code&gt;graphql&lt;/code&gt;, &lt;code&gt;grafast&lt;/code&gt; and &lt;code&gt;@dataplan/pg&lt;/code&gt; which contains all the step classes to help Gra&lt;em&gt;fast&lt;/em&gt; deal with PostgreSQL.&lt;/p&gt;

&lt;p&gt;Why should you care? Well, a number of reasons!&lt;/p&gt;

&lt;h2&gt;
  
  
  Perfect for Serverless
&lt;/h2&gt;

&lt;p&gt;Building a PostGraphile schema takes a moment, and in serverless contexts you don't want to incur that overhead every time you boot up your serverless function. Cold start times can now be reduced by just running the final schema without any build steps. For a non-trivial schema consisting of 201 different GraphQL types, this results in just 186ms to start node, import the schema, count the types, and shut down again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time &lt;/span&gt;node &lt;span class="nt"&gt;--input-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;module &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'import { schema } from "./exported-schema.mjs"; console.log(Object.keys(schema.getTypeMap()).length)'&lt;/span&gt;
201
real    0m0.186s
user    0m0.213s
sys     0m0.011s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For reference, it takes 29ms to import a file just containing the statement &lt;code&gt;1 + 2;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"1 + 2;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; one_plus_two.mjs
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time &lt;/span&gt;node &lt;span class="nt"&gt;--input-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;module &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'import "./one_plus_two.mjs"; console.log("done")'&lt;/span&gt;
&lt;span class="k"&gt;done
&lt;/span&gt;real    0m0.029s
user    0m0.029s
sys     0m0.000s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you webpack the resulting file, then you can eliminate the filesystem overhead of all the imports, and the time comes down even further to just 115ms (only 86ms longer than the &lt;code&gt;one_plus_two.mjs&lt;/code&gt; baseline file!):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time &lt;/span&gt;node &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'console.log(Object.keys(require("./exported-schema.webpacked.js").schema.getTypeMap()).length)'&lt;/span&gt;
201
real    0m0.115s
user    0m0.097s
sys     0m0.021s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even better, because the number of dependencies have been significantly reduced, you also end up with a much smaller bundle size when webpacked than you would with V4, which means it's faster to unzip, reducing cold start time even further!&lt;/p&gt;

&lt;h2&gt;
  
  
  Improved Visibility
&lt;/h2&gt;

&lt;p&gt;It can sometimes be hard to understand what an automagically built GraphQL schema is doing, which makes modifying it challenging. By exporting your schema, you can read through the final plan resolver code — code which we've put a significant effort into making as straightforward as we can reasonably make it! This can help you to grok the system, and then extend or customize it based on your own needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.graphile.org/ext/exported-example.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9gd30afjffzc6zdccujv.png" alt="Terminal screenshot in two columns, left column showing JS code and right showing GraphQL schema definition language." width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
An excerpt from an exported schema showing a number of simple fields and a more complex field that uses a connection and has argument subplans.
&lt;/p&gt;



&lt;h2&gt;
  
  
  Eject Button
&lt;/h2&gt;

&lt;p&gt;For those who are worried about adopting PostGraphile because they don't want to be locked into an auto–generated GraphQL schema forever, you now have a way to export the code from your generated schema and then manage that for yourself from then onwards, with no dependency on &lt;code&gt;graphile-build&lt;/code&gt;, &lt;code&gt;graphile-build-pg&lt;/code&gt; or even &lt;code&gt;postgraphile&lt;/code&gt; itself!&lt;/p&gt;

&lt;h2&gt;
  
  
  It's not just for PostGraphile
&lt;/h2&gt;

&lt;p&gt;A wonderful feature of this module is that it isn't limited to PostGraphile — you could use this with other systems that build a GraphQL schema dynamically (even if that schema is generated by a "builder API" rather than auto–generation) in order to make your GraphQL schema start as fast as possible in production! Long term, I'd like to make it so we can even use babel plugins or similar rather than having to add &lt;code&gt;EXPORTABLE()&lt;/code&gt; wrappers, but that's not a priority right now 🙂&lt;/p&gt;

&lt;p&gt;And speaking of compatibility…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Check back next week when Benjie will be talking about compatibility, and remember: to get your hands on a pre–release version of PostGraphile V5, all you need to do is sponsor Graphile at any tier and then drop us an email or DM! Find out more at &lt;a href="http://graphile.org/sponsor" rel="noopener noreferrer"&gt;graphile.org/sponsor&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>postgraphile</category>
      <category>graphql</category>
      <category>node</category>
      <category>codegen</category>
    </item>
    <item>
      <title>Intro to PostGraphile V5 (Part 5): Polymorphism!</title>
      <dc:creator>Benjie</dc:creator>
      <pubDate>Fri, 21 Jul 2023 10:56:04 +0000</pubDate>
      <link>https://dev.to/graphile/intro-to-postgraphile-v5-part-5-polymorphism-40b4</link>
      <guid>https://dev.to/graphile/intro-to-postgraphile-v5-part-5-polymorphism-40b4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Benjie is the community–funded maintainer of the Graphile suite — a collection of MIT–licensed Node.js developer tooling for GraphQL and/or PostgreSQL. A key project in this suite is PostGraphile, a high performance, customizable and extensible GraphQL schema generator for APIs backed primarily (but not exclusively!) by PostgreSQL.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is part five in the "Intro to PostGraphile V5" series, which started with &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-1-replacing-the-foundations-3lh0"&gt;Part 1: Replacing the Foundations&lt;/a&gt;. This week, Benjie takes a look at how&lt;/em&gt; Gra&lt;em&gt;fast&lt;/em&gt; &lt;em&gt;enables PostGraphile to support polymorphism; you can get your hands on the pre–release now by becoming a sponsor — see &lt;a href="https://postgraphile.org/" rel="noopener noreferrer"&gt;postgraphile.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Polymorphism in GraphQL is where a field can return different types of things. For example a field might state it will return a &lt;code&gt;Pet&lt;/code&gt;, but at runtime that must actually be a &lt;code&gt;Cat&lt;/code&gt; or a &lt;code&gt;Dog&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above case, &lt;code&gt;Pet&lt;/code&gt; is an interface type which means that every type it can be has to implement at least the shared fields.&lt;/p&gt;

&lt;p&gt;However, there are also situations where there aren't shared fields — for example your morning alarm might be your phone, or it might be your hungry cat — for these, we use a union type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MorningAlarm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Device&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Device&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Polymorphism can be very important in GraphQL APIs, and yet has been traditionally overlooked in PostGraphile due to the complexity of implementing it in the old look–ahead system, and concerns over runtime performance. In fact it's one of our longest running issue threads: &lt;a href="https://github.com/graphile/postgraphile/issues/387" rel="noopener noreferrer"&gt;https://github.com/graphile/postgraphile/issues/387&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;But no more!&lt;/p&gt;

&lt;p&gt;Thanks to the magic that is Gra&lt;em&gt;fast&lt;/em&gt;, we now support both interfaces and unions at the planning layer, and you can now use smart tags to indicate to PostGraphile that a given table (or set of tables) is polymorphic so that PostGraphile will automatically generate the interfaces/unions and types for you!&lt;/p&gt;

&lt;p&gt;We support a number of patterns of polymorphism in your PostgreSQL database, the most common of which is probably the &lt;a href="https://en.wikipedia.org/wiki/Single_Table_Inheritance" rel="noopener noreferrer"&gt;"single table inheritance"&lt;/a&gt; pattern, where you have a table containing a &lt;code&gt;type&lt;/code&gt; column indicating the type of the row, and columns for all the different attributes that the different types may need. We also support "relational polymorphism" where a central table represents an interface and stores all the common attributes (plus the type), and then this table is one–to–one joined to another table (depending on the &lt;code&gt;type&lt;/code&gt;) which has additional columns specific to that type.&lt;/p&gt;

&lt;p&gt;Unions are much simpler, you can simply declare that any of your tables belongs to a particular union via the &lt;code&gt;@unionMember&lt;/code&gt; smart tag, and that union will be created if it didn't already exist, and the table added to it.&lt;/p&gt;

&lt;p&gt;We also support more exotic forms of polymorphism, including a many–join–tables polymorphism pattern that Netflix uses with PostGraphile V5, and Gra&lt;em&gt;fast&lt;/em&gt; is flexible enough that we can add more patterns over time if the need arises! It's worth keeping in mind that Gra&lt;em&gt;fast&lt;/em&gt; itself is completely independent of data source, so though we have built in a number of optimized polymorphic patterns for Postgres into PostGraphile, Gra&lt;em&gt;fast&lt;/em&gt; users can leverage flexible polymorphism no matter what data sources they are using. &lt;/p&gt;

&lt;p&gt;If you have access to the V5 documentation, you can read more about it here: &lt;a href="https://postgraphile.org/postgraphile/next/polymorphism" rel="noopener noreferrer"&gt;https://postgraphile.org/postgraphile/next/polymorphism&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This has been one of the most eagerly anticipated features of PostGraphile V5, and I'm extremely excited to announce that not only is it now, finally, possible; but it has been since late last year and the early adopters are getting on well with it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrlr3jhu6g8n9yak2ap2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrlr3jhu6g8n9yak2ap2.png" alt="Discord message from Mo Binni: " width="800" height="165"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A happy user of V5 polymorphism.&lt;/p&gt;



&lt;p&gt;Next up, another massive feature of V5 that'll be loved by serverless aficionados and people concerned about being locked into a PostGraphile schema alike!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;del&gt;Check back next week to find out what the next new feature is&lt;/del&gt; Next, check out &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-6-excellent-executable-exports-1150"&gt;Intro to PostGraphile V5 (Part 6): Excellent Executable Exports&lt;/a&gt;; and remember: to get your hands on a pre–release version of PostGraphile V5 including all its polymorphic goodness, all you need to do is sponsor Graphile at any tier and then drop us an email or DM! Find out more at &lt;a href="http://graphile.org/sponsor" rel="noopener noreferrer"&gt;graphile.org/sponsor&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>postgraphile</category>
      <category>graphql</category>
      <category>postgres</category>
      <category>polymorphism</category>
    </item>
    <item>
      <title>Intro to PostGraphile V5 (Part 4): Making the Schema Yours</title>
      <dc:creator>Benjie</dc:creator>
      <pubDate>Tue, 11 Jul 2023 15:33:05 +0000</pubDate>
      <link>https://dev.to/graphile/intro-to-postgraphile-v5-part-4-making-the-schema-yours-57h4</link>
      <guid>https://dev.to/graphile/intro-to-postgraphile-v5-part-4-making-the-schema-yours-57h4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Benjie is the community–funded maintainer of the Graphile suite — a collection of MIT–licensed Node.js developer tooling for GraphQL and/or PostgreSQL. A key project in this suite is PostGraphile, a high performance, customizable and extensible GraphQL schema generator for APIs backed primarily (but not exclusively!) by PostgreSQL.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is part four in the "Intro to PostGraphile V5" series, which started with &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-1-replacing-the-foundations-3lh0"&gt;Part 1: Replacing the Foundations&lt;/a&gt;. This week, Benjie takes a look at the new behaviour system coming to PostGraphile Version 5, available in pre–release now for all Graphile sponsors, find out more at &lt;a href="https://postgraphile.org/" rel="noopener noreferrer"&gt;postgraphile.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In PostGraphile Version 4, despite the automatic nature of the GraphQL schema generation, we wanted you to be able to exert significant influence over the shape of the final schema. One main way of achieving this was by using the pre–existing permissions in the database — things that were not &lt;code&gt;GRANT&lt;/code&gt;–ed in the database would not be exposed by GraphQL. For finer grained control we added the &lt;code&gt;@omit&lt;/code&gt; &lt;a href="https://www.graphile.org/postgraphile/smart-tags/" rel="noopener noreferrer"&gt;smart tag&lt;/a&gt; which you could attach to database resources (tables, views, columns, constraints, functions, etc) in order to have them be omitted from certain scenarios (listing all rows, ordering, filtering, etc). &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@omit&lt;/code&gt; system handled a lot of customization needs, but there were still parts of the auto–generation which couldn’t be affected this way. For example, we didn't have a way to just omit root–level single record accessor fields (e.g. &lt;code&gt;Query.userByUsername&lt;/code&gt;), so you would have to write a plugin to remove the field after it was added while navigating around the caveats this entailed.&lt;/p&gt;

&lt;p&gt;By its very nature, the &lt;code&gt;@omit&lt;/code&gt; system was a block–list rather than an allow–list; this was suitable for most who only wanted to make small changes, but some users would rather start with a clean slate and build up. Sadly, we couldn't add an allow–list equivalent because it would cause breaking changes as we added more &lt;code&gt;@omit&lt;/code&gt;–able things: things would suddenly disappear from your schema. Not tenable.&lt;/p&gt;

&lt;p&gt;It was clear that we would need a better system in Version 5 — it needed to be able to do everything the V4 system could do, and more. It needed to be both an allow–list and a block–list. It needed to be configurable globally, with local overrides, and perhaps even–more–local–still overrides… like globally disabling updates by default, then re–enabling updates on a given table, but then disabling it on a particular unique constraint (e.g. to turn off &lt;code&gt;Mutation.updateUserByUsername&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now where had I seen something like this before? 🤔&lt;/p&gt;

&lt;p&gt;Feature flags!&lt;/p&gt;

&lt;p&gt;I created the concept of &lt;code&gt;@behavior&lt;/code&gt; strings, inspired by feature flags, giving the user granular control over entity behaviour. You could add &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;-&lt;/code&gt; in front of a feature string to determine if that feature should be enabled or disabled respectively, features can be scoped to very granular locations, and by having &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-2-plugins-and-presets-26fe"&gt;presets&lt;/a&gt; specify default behaviours we could evolve the system over time without breaking changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.graphile.org/ext/behavor-string.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60242eq3w0be9u5ficdx.png" alt="Diagram depicting a behavior string constructed from '-create -update -delete' (don't add create, update or delete mutations), '-list +connection' (Don't use lists, do use connections) and '-query:resource:connection' (Don't add a connection field at the query root)" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
A user can build their behaviour string in an incremental way, using optional &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;-&lt;/code&gt; to indicate inclusion or omission. The rightmost value is the most significant, the system scans backwards looking for the first match, then uses the &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;-&lt;/code&gt; modifier to determine if the behaviour is enabled or not.
&lt;/p&gt;



&lt;p&gt;These behaviour strings are built up by simple concatenation as we navigate through from plugin default behaviours, to the global default behaviour configured in your preset, to the table's behaviour, then to the specific column/constraint's behaviour. When taking an action (e.g. adding an "update" mutation, creating an "order by" enum, etc.) the system scans back through the resulting behaviour string to see if that action is enabled (&lt;code&gt;+&lt;/code&gt;) or not (&lt;code&gt;-&lt;/code&gt;); it’s that simple!&lt;/p&gt;

&lt;p&gt;At long last, with this system, you can exert per–field, per–type, per–argument control over the generated GraphQL schema without having to drop down into the plugin layer to manually delete things. It even replaces things like &lt;code&gt;simpleCollections&lt;/code&gt; because you now choose whether you want a list, connection, both or neither via the behaviour.&lt;/p&gt;

&lt;p&gt;Sponsors can read more about the new behaviour system here: &lt;a href="https://postgraphile.org/postgraphile/next/behavior" rel="noopener noreferrer"&gt;https://postgraphile.org/postgraphile/next/behavior&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Speaking of having greater control over your GraphQL schema, there has been something which has been requested numerous times over the years, but V4 could not support it… It begins with a "P", and if you've been paying close attention to this series you might already know what it is…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;del&gt;Check back next week to find out what the next new feature is&lt;/del&gt; You've guessed it — it was &lt;strong&gt;polymorphism&lt;/strong&gt; 🎉 Check it out in &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-5-polymorphism-40b4"&gt;Intro to PostGraphile V5 (Part 5): Polymorphism!&lt;/a&gt;; and remember: to get your hands on a pre–release version of PostGraphile V5, all you need to do is sponsor Graphile at any tier and then drop us an email or DM! Find out more at &lt;a href="http://graphile.org/sponsor" rel="noopener noreferrer"&gt;graphile.org/sponsor&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>postgraphile</category>
      <category>postgres</category>
      <category>graphql</category>
      <category>news</category>
    </item>
    <item>
      <title>Intro to PostGraphile V5 (Part 3): Introspection and Abstraction</title>
      <dc:creator>Benjie</dc:creator>
      <pubDate>Wed, 05 Jul 2023 15:42:47 +0000</pubDate>
      <link>https://dev.to/graphile/intro-to-postgraphile-v5-part-3-introspection-and-abstraction-2k7n</link>
      <guid>https://dev.to/graphile/intro-to-postgraphile-v5-part-3-introspection-and-abstraction-2k7n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Benjie is the community–funded maintainer of the Graphile suite — a collection of MIT–licensed Node.js developer tooling for GraphQL and/or PostgreSQL. A key project in this suite is PostGraphile, a high performance, customizable and extensible GraphQL schema generator for APIs backed primarily (but not exclusively!) by PostgreSQL.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is part three in the "Intro to PostGraphile V5" series, which started with &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-1-replacing-the-foundations-3lh0"&gt;Part 1: Replacing the Foundations&lt;/a&gt;. This week, Benjie talks about his new introspection and schema generation system, and how it leads to improved type safety, documentation, and better compatibility. This new system is coming in PostGraphile Version 5, available in pre–release now for all Graphile sponsors, find out more at &lt;a href="https://postgraphile.org/" rel="noopener noreferrer"&gt;postgraphile.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For PostGraphile to be able to build an API based on your PostgreSQL database, it needs to know what your database contains: what are the schemas, tables, columns, indexes, constraints, functions, views, grants, etc. To do this, it uses a technique called "introspection": it issues SQL &lt;code&gt;SELECT&lt;/code&gt; statements against the "system catalog," effectively having the database describe itself. PostGraphile (and previously PostGraphQL) has done this since the very beginning of the project.&lt;/p&gt;

&lt;p&gt;PostGraphile V4 inherited its introspection query from PostGraphQL v3, v3 from v2, and v2 from v1. Each version added tweaks, enhanced support for various entities, or improved compatibility with newer versions of PostgreSQL, but the structure remained similar throughout. The result was a very PostGraphile–specific introspection query, with its own documentation and typing needs, a lot of accommodations for different PostgreSQL versions, and very poor compatibility with PostgreSQL–alike databases, such as Cockroach DB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meanwhile, during consulting…
&lt;/h2&gt;

&lt;p&gt;Whilst reviewing various PostGraphile–based client projects, I noticed a number of very common issues that people would have in their database schemas. Things like forgetting to enable row level security on a table despite creating policies for it (a major security issue!), forgetting to create indexes on foreign key constraints (making reverse lookups often require table scans — a major performance issue) and other such things. I came up with a large number of rules, and wrote a system that could detect these problems, which you can use at &lt;a href="https://pgrita.com" rel="noopener noreferrer"&gt;https://pgrita.com&lt;/a&gt; . It's a little rough around the edges (PostGraphile V5 has taken all my attention recently), but it packs a hell of a lot of value for its early access price of just $25/mo. There's even a free plan!&lt;/p&gt;

&lt;p&gt;Whilst building pgRITA I needed to support lots of different PostgreSQL versions, and I needed an easy way to deal with the introspection results from them — not least making sure I didn't make typos, and knowing what fields like &lt;code&gt;attinhcount&lt;/code&gt; &lt;a href="https://www.postgresql.org/docs/current/catalog-pg-attribute.html" rel="noopener noreferrer"&gt;even meant&lt;/a&gt;. So I built something that parsed the PostgreSQL documentation and converted it into TypeScript types, with documentation built in via TSDoc. It was delightful, and made writing the rules for pgRITA much easier. It even knew which properties were common to all the different PostgreSQL versions, versus which ones might only be in earlier or later versions and marking them as optional (using &lt;code&gt;?&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  A new hero arises…
&lt;/h2&gt;

&lt;p&gt;When it came time to build the introspection for PostGraphile V5, I decided not to reuse the introspection query that had served us well for the past 7 years. I had something better to base it on: the pgRITA system. Some customization later and &lt;strong&gt;I'm proud to announce the &lt;a href="https://www.npmjs.com/package/pg-introspection" rel="noopener noreferrer"&gt;&lt;code&gt;pg-introspection&lt;/code&gt;&lt;/a&gt; library&lt;/strong&gt; — a fully–typed introspection library for PostgreSQL. It's already out on npm, and you can use it for any other projects too! Don't worry that it's not had any updates in a number of months, it's essentially "finished" and will only need updates when breaking versions of PostgreSQL (or TypeScript) come out.&lt;/p&gt;

&lt;p&gt;This new system has many advantages over the old one: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it's much easier to keep in sync with new PostgreSQL versions because it's generated from the documentation,&lt;/li&gt;
&lt;li&gt;it doesn't need a different query for different versions of PostgreSQL because it rarely references the columns directly, instead using &lt;code&gt;SELECT *&lt;/code&gt; or similar techniques,&lt;/li&gt;
&lt;li&gt;it doesn't need as much documentation (or custom TypeScript types) because these are auto–generated,&lt;/li&gt;
&lt;li&gt;it works better with Postgres–alikes because it doesn't use as many fancy query features,&lt;/li&gt;
&lt;li&gt;it’s easier to understand thanks to being generated — it reuses many of the same patterns which makes the structure uniform and consistent.,&lt;/li&gt;
&lt;li&gt;we've augmented it with a number of helpers to make life easier,&lt;/li&gt;
&lt;li&gt;and much more.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Revisiting abstractions
&lt;/h2&gt;

&lt;p&gt;A question remained though. In V4, plugins would use the introspection results directly to generate the types, fields, args, etc in our GraphQL API. Was this what we wanted for V5? One issue with the V4 approach is that when you make breaking changes there’s no easy way to "fake" a duplicate table to support the deprecated usage patterns whilst moving everything over to the new way. &lt;/p&gt;

&lt;p&gt;I'm a big believer in GraphQL (in fact, at time of writing I'm &lt;a href="https://github.com/graphql/graphql-spec/graphs/contributors" rel="noopener noreferrer"&gt;#2 contributor&lt;/a&gt; to the GraphQL spec itself) so it pains me that a tool I built doesn't always have easy ways to achieve the "&lt;a href="https://graphql.org/learn/best-practices/#versioning" rel="noopener noreferrer"&gt;versionless schema&lt;/a&gt;" design that GraphQL encourages when it comes to making significant breaking changes to your underlying database tables. (Personally, I think you should aim for your database schema itself to be versionless, but this is not always possible.) Of course you can build your PostGraphile schema over views instead of tables, but views have their own problems that I won't go into here…&lt;/p&gt;

&lt;p&gt;“No,” I thought to myself, “clearly the V4 approach had problems. There should be an intermediate layer. And I'm rebuilding everything, so why not?”&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing build phases
&lt;/h2&gt;

&lt;p&gt;Leveraging our new plugin system's scopes, I split the schema building into four phases: &lt;code&gt;inflection&lt;/code&gt; (naming things), &lt;code&gt;gather&lt;/code&gt; (performing introspection and similar tasks), &lt;code&gt;behavior&lt;/code&gt; (which we'll look at next week) and &lt;code&gt;schema&lt;/code&gt; (actually building the schema, synchronously, based on the previous phases' outputs).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;inflection&lt;/code&gt; phase registers a number of "inflector" functions, named by &lt;em&gt;purpose&lt;/em&gt;, that accept as input a description of an &lt;em&gt;entity&lt;/em&gt; and return a string to be used as the name for that entity for that purpose (e.g. when creating (&lt;em&gt;the&lt;/em&gt; &lt;em&gt;purpose&lt;/em&gt;) a user (&lt;em&gt;the&lt;/em&gt; &lt;em&gt;entity&lt;/em&gt;) you might want the mutation field name &lt;code&gt;createUser&lt;/code&gt;, or &lt;code&gt;userCreate&lt;/code&gt;, or even &lt;code&gt;create_a_user&lt;/code&gt; — with inflection, it's up to you). Importantly, inflectors can be added but they can also be replaced; the replacement has access to the previous inflector allowing it to add to, augment, or fully replace the previous value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.graphile.org/ext/graphile-inflection-list.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvtl43t95n9bcf9otlzg4.png" alt="Terminal output: white text on black background with colourised TypeScript types, outputting in markdown format the beginnings of the inflector documentation" width="654" height="289"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
The initial output of the new &lt;code&gt;graphile inflection list&lt;/code&gt; command, including a summary of the available inflectors and their arguments.
&lt;/p&gt;



&lt;p&gt;Next up is the &lt;code&gt;gather&lt;/code&gt; phase, during which all the information necessary to build the GraphQL schema is brought together. This includes things like the introspection results from the PostgreSQL database, row values in enum tables, and anything else essential which needs to be fetched from a remote source. At the end of the gather phase an "input" object is produced, ready to be fed into the next phase. This object currently consists of "resources", "codecs” and the relations between them. Resources describe things that PostGraphile can pull data from: tables, views, functions, etc. Codecs describe the data and how to parse it from (or serialize it to) the database; and not just the base types such as int, float, text — codecs also cover more complex things like arrays, domains, and composite types (records).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;behavior&lt;/code&gt; phase squeezes in just before the schema phase, and gives a chance to indicate or override what the specific behaviour of each of the codecs, resources and relationships will be. We'll look more at this next week.&lt;/p&gt;

&lt;p&gt;Finally, is the &lt;code&gt;schema&lt;/code&gt; phase. The schema phase takes the "input" object produced by the &lt;code&gt;gather&lt;/code&gt; phase and – by applying all the schema hook callbacks – uses it to synchronously build out the GraphQL schema. It's important to note that unlike the &lt;code&gt;gather&lt;/code&gt; phase, the &lt;code&gt;schema&lt;/code&gt; phase can be synchronous because any asynchronous data fetching should already have been done in the &lt;code&gt;gather&lt;/code&gt; phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bring your own resources
&lt;/h2&gt;

&lt;p&gt;An interesting feature of this system is that you don't actually &lt;em&gt;need&lt;/em&gt; a &lt;code&gt;gather&lt;/code&gt; phase at all — you could describe your tables, columns and functions yourself and have the schema be generated from these descriptions. Or you can combine the gather phase with a post–processing step where you copy a source with a few changes and a different name in order to back–fill your backwards compatibility needs. You can also &lt;code&gt;gather&lt;/code&gt; from multiple different databases, building a GraphQL schema from multiple PostgreSQL databases without your schema consumers being any the wiser. It's a very powerful feature!&lt;/p&gt;

&lt;p&gt;Of course it's critical when using a (mostly) auto–generated schema that you can hone its shape easily and quickly, hence the behaviour system we'll talk about next time…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;del&gt;Next week, Benjie will be discussing how Version 5 users can customize and shape their GraphQL schema using a globally configurable behaviour system&lt;/del&gt; Next, check out &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-4-making-the-schema-yours-57h4"&gt;Intro to PostGraphile V5 (Part 4): Making the Schema Yours&lt;/a&gt;; and remember: to get your hands on a pre–release version of PostGraphile V5, all you need to do is sponsor Graphile at any tier and then drop us an email or DM! Find out more at &lt;a href="http://graphile.org/sponsor" rel="noopener noreferrer"&gt;graphile.org/sponsor&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>postgraphile</category>
      <category>graphql</category>
      <category>postgres</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Intro to PostGraphile V5 (Part 2): Plugins and Presets</title>
      <dc:creator>Benjie</dc:creator>
      <pubDate>Tue, 27 Jun 2023 15:16:44 +0000</pubDate>
      <link>https://dev.to/graphile/intro-to-postgraphile-v5-part-2-plugins-and-presets-26fe</link>
      <guid>https://dev.to/graphile/intro-to-postgraphile-v5-part-2-plugins-and-presets-26fe</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Benjie is the community–funded maintainer of the Graphile suite — a collection of MIT–licensed Node.js developer tooling for GraphQL and/or PostgreSQL. A key project in this suite is PostGraphile, a high performance, customizable and extensible GraphQL schema generator for APIs backed primarily (but not exclusively!) by PostgreSQL.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is part two in the "Intro to PostGraphile V5" series, which started with &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-1-replacing-the-foundations-3lh0"&gt;Part 1: Replacing the Foundations&lt;/a&gt;. This week, Benjie takes a look at PostGraphile V5's new unified plugin and preset system.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In PostGraphile V4, we had two different types of plugins: &lt;a href="https://www.graphile.org/postgraphile/extending/" rel="noopener noreferrer"&gt;schema plugins&lt;/a&gt; (the original plugins; they control how the GraphQL schema is built: adding types, fields, arguments, etc) and &lt;a href="https://www.graphile.org/postgraphile/plugins/" rel="noopener noreferrer"&gt;server plugins&lt;/a&gt; (these came later and allowed you to manipulate the HTTP request lifecycle, add validation rules, customize GraphiQL, add CLI arguments and all that good stuff). These two different types of plugins worked in completely different ways and were added to the system in four different ways — two for the CLI, and two in API mode. Confusing, right?&lt;/p&gt;

&lt;p&gt;Worse, as PostGraphile V4 advanced and we learned alongside the community what the best practices were, the recommended settings would evolve. But we couldn't change the defaults because that would break all existing user's schemas. To me, a major release is a major thing — we shouldn't have one every time I want to change a default — so I kept a list of recommended options up to date in the documentation and hoped that new users would use them. We managed to do 41 releases of PostGraphile 4.x over the course of 5 years, all without a major breaking change! But the situation with default options was not ideal.&lt;/p&gt;

&lt;p&gt;And worst of all, there were those &lt;a href="https://www.graphile.org/postgraphile/usage/" rel="noopener noreferrer"&gt;4 different ways of configuring PostGraphile&lt;/a&gt;. You could use the CLI, in which case you could pass CLI flags. If you started getting too many CLI flags, you might switch to using the RC file, which would get merged in with the parsed CLI flags before being passed to the library. The RC file didn’t line up with the library options; nor did it quite line up with the CLI flags because, while it was derived from them, it used a format of its own — initially a quick tweak to enable greater flexibility, the RC file became a separate beast which needed its own documentation. Then we also had the library options for when you were using PostGraphile as middleware inside your existing Express/Koa/Fastify/etc server. And finally we had the schema–only options, which were a stripped down set from the library options applicable when using the schema with no server.&lt;/p&gt;

&lt;p&gt;Ugh. So much to document!&lt;/p&gt;

&lt;p&gt;It's clear this system evolved over time, and was patched together in the dribs and drabs of time I had available. Well, no more! With a significant amount of sponsorship behind me this time, I could do it right.&lt;/p&gt;

&lt;p&gt;It was obvious &lt;strong&gt;I wanted a system that could evolve the defaults over time without major breaking changes&lt;/strong&gt;. A "preset" system, where you could pull down the Jan2023 preset, or the Sept2025 preset, and stick with that as your base for the lifetime of your project. Clearly presets would need to be able to "extend" other presets, we don't want to have to populate every single option in every preset. And, in fact, why not make it so the user's own config is a preset — whether they're using CLI, library or schema–only modes?&lt;/p&gt;

&lt;h3&gt;
  
  
  Choose your flavour
&lt;/h3&gt;

&lt;p&gt;Though I've long believed that GraphQL APIs aren’t a one–size–fits–all problem space — hence making PostGraphile so configurable and extensible — through experience with users and sponsors it's clear there are certain classes of use cases that are common:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some expose their GraphQL APIs directly over the web. For them it's critical that their schema is small and straightforward with nothing that could cause performance or security issues.&lt;/li&gt;
&lt;li&gt;Some leverage persisted operations to guarantee that only a preset list of queries will be accepted by the server. For these the schemas can be larger and expose more capabilities, trusting the frontend engineers to make sure the queries are performant.&lt;/li&gt;
&lt;li&gt;Some use PostGraphile to share data internally within their organization in an easy to query format. These users typically want to expose as much of Postgres' power as possible without having to give actual SQL access to the database, typically enabling features that would be a poor fit for most consumer–facing APIs.&lt;/li&gt;
&lt;li&gt;Some are in the prototyping phase and want to see what's possible, before they make their decisions and narrow down their schema later. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And on top of these "feature" decisions, there's also "style" to consider. Powerful and extensible connections, or simple and performant lists? Relay-focused global object identifiers, or straightforward database primary keys? Start with an empty schema and add things as you need them, or start with a expansive schema and remove things you don't need?&lt;/p&gt;

&lt;p&gt;With this experience and these needs in mind, I started planning the new system. To simplify things for users there would be just one type of plugin. Presets would compose other presets, plugins, and scoped configuration options. These new presets and plugins would be enabled via the new &lt;code&gt;graphile-config&lt;/code&gt; module which would handle common concerns such as merging presets and ordering plugins. Plugins and presets would contain "scopes" that relate to different parts of the system, so a plugin could choose to affect the schema, or the server, or both. And if a plugin details a scope that is not relevant to the current situation, for example a "server" scope when using “schema–only”, then that would simply be ignored thanks to the system using declarative objects rather than the previous procedural-style hooks.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are my options?
&lt;/h3&gt;

&lt;p&gt;Thanks to the declarative and strongly-typed nature of the new system, I've expanded our new &lt;code&gt;graphile&lt;/code&gt; command (a toolbelt for handy utilities) with configuration-based subcommands. One command, &lt;code&gt;graphile config print&lt;/code&gt;, outputs the resolved preset (after merging in all the other presets that your preset extends) which is very useful for debugging and getting an understanding of all of the features that your combination of presets have enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.graphile.org/ext/graphile-config-print-screenshot.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftkxmx6j50e2vxzldxkpl.png" alt="Screenshot excerpt from a terminal with black background, showing a list of plugins in green, and the configuration of various scopes with the scope name in white and option names below in blue with values in various colours depending on type." width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
The output from &lt;code&gt;graphile config print&lt;/code&gt; resolves all of the presets you're using and then lists your enabled plugins in order accompanied by their versions and descriptions, followed by the options used in each of the registered scopes.
&lt;/p&gt;



&lt;p&gt;Another command, &lt;code&gt;graphile config options&lt;/code&gt;, outputs a reference to all of the configuration options that you have available to you. Importantly, &lt;strong&gt;this is specific to your project&lt;/strong&gt;, based on the modules that you're importing in your &lt;code&gt;graphile.config.*&lt;/code&gt; file. Via the magic of TypeScript it can even extract the documentation for each option from the various modules' TSDoc comments! And furthermore, the output is in markdown, so you can write it to a file to act as configuration documentation for your project. Honestly, I love it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://graphile.org/ext/graphile-config-options-screenshot.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4phmg9791gmvx8adkixt.png" alt="Screenshot excerpt from a terminal with black background, white text and highlights in bold white, blue and green." width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
The &lt;code&gt;graphile config options&lt;/code&gt; command details all of the options that you can use in your configuration file. Output in a colourful markdown style, it includes the documentation for each option along with the type — all extracted from the TypeScript source so you know it's up to date!
&lt;/p&gt;



&lt;p&gt;Having now built V5's unified plugins and presets system, I'm extremely pleased with it! I'm so happy, in fact, that I'm looking forward to integrating it with Graphile's other tools such as &lt;a href="https://github.com/graphile/worker" rel="noopener noreferrer"&gt;Graphile Worker&lt;/a&gt; (our Postgres-backed job queue) and &lt;a href="https://github.com/graphile/migrate" rel="noopener noreferrer"&gt;Graphile Migrate&lt;/a&gt; (a lightweight SQL-based migration framework that focuses on DX) once V5 is out and stable.&lt;/p&gt;

&lt;p&gt;But standardization of the configuration of PostGraphile across all the usage modes is a minor feature compared to some of the other things coming in V5…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;del&gt;Check back next week for&lt;/del&gt; Next, check out &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-3-introspection-and-abstraction-2k7n"&gt;Part 3: Introspection and TypeScript&lt;/a&gt;; and remember: to get your hands on a pre-release version of PostGraphile V5, all you need to do is sponsor Graphile at any tier and then drop us an email! Find out more at &lt;a href="http://graphile.org/sponsor" rel="noopener noreferrer"&gt;graphile.org/sponsor&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>postgraphile</category>
      <category>graphql</category>
      <category>postgres</category>
      <category>node</category>
    </item>
    <item>
      <title>Intro to PostGraphile V5 (Part 1): Replacing the Foundations</title>
      <dc:creator>Benjie</dc:creator>
      <pubDate>Tue, 20 Jun 2023 15:21:39 +0000</pubDate>
      <link>https://dev.to/graphile/intro-to-postgraphile-v5-part-1-replacing-the-foundations-3lh0</link>
      <guid>https://dev.to/graphile/intro-to-postgraphile-v5-part-1-replacing-the-foundations-3lh0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Benjie is the community–funded maintainer of the Graphile suite — a collection of MIT–licensed Node.js developer tooling for GraphQL and/or PostgreSQL. A key project in this suite is PostGraphile, a high performance, customizable and extensible GraphQL schema generator for APIs backed primarily (but not exclusively!) by PostgreSQL.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In this post Benjie tells his story of bringing a new paradigm to PostGraphile to enable it to become more powerful and performant than ever before — this new system is coming in PostGraphile Version 5, available in pre–release now for all Graphile sponsors, find out more at &lt;a href="https://postgraphile.org" rel="noopener noreferrer"&gt;postgraphile.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Something was fundamentally problematic in the design of PostGraphile Version 4 — the look–ahead system. The system that gave PostGraphile its power and performance was also the system that made it hard to maintain and hard to add new functionality to. Though few ever needed to interact with it directly, it was hard to teach those who did how to use the look–ahead system when even I struggled with it — and I was the one who wrote it! I built abstractions to make the common tasks more straightforward for users, but everything needed its own little helper, and the helpers were inconsistent. Messy. Verbose.&lt;/p&gt;

&lt;p&gt;I wanted PostGraphile V5 to support all the new features of GraphQL, but even patching well–established features such as polymorphism into the look–ahead system seemed insurmountable — it wasn’t built with that in mind. This was hardly a surprise, the original system was hacked together in just 2 weeks! I needed a better solution…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It was February 2020&lt;/strong&gt;. I had returned from the &lt;a href="https://fosdem.org/" rel="noopener noreferrer"&gt;FOSDEM&lt;/a&gt; conference in Brussels and was lying sick in bed with a fever. (Immunosuppressants and conferences are not a winning combination.) As I went in and out of fevers, a thought struck me… &lt;strong&gt;What if instead of writing code that executes, we wrote code that &lt;em&gt;described&lt;/em&gt; the execution.&lt;/strong&gt; GraphQL is declarative, but resolvers are procedural… What if, instead, we made declarative resolvers?&lt;/p&gt;

&lt;p&gt;When I could lift my head without the room spinning, I scribbled some notes in my notebook. I started by doing what I hadn't with look–ahead: focusing on the code the users would write. In fact, that's all I focused on, and just kept telling myself that all the information the system needed was there in that code… I just needed to build a system that could understand and execute it. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.graphile.org/ext/notebook.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32fqcs333dqxf396poyw.png" alt="A photo of an A4 notebook with lined paper and scrawly handwriting in multiple pen colours talking about 'plans' and various other technical details that are hard to extract" width="800" height="1069"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
The page that got it all started! Scribbled out in Feb 2020 (over multiple sittings). Though the planning system has evolved since then, you can still see a lot of the things that Gra&lt;em&gt;fast&lt;/em&gt; has today!
&lt;/p&gt;



&lt;p&gt;That turned out to be a long process with many false starts. Over the 3 years I spent working on this project (on and off, between client work and open source responsibilities, grabbing a few hours here and there to peck away at it) I rewrote the engine 5 times. Each time I ended up with something that worked, mostly, but it would fail at some point near the end due to some slight oversight, each time making me revisit the drawing board.&lt;/p&gt;

&lt;p&gt;Throughout these rewrites, the "plan resolver" code that users would write (or PostGraphile would generate for you) barely changed — it was just the engine that needed to evolve. "Plan resolvers" differ from traditional GraphQL resolvers in that instead of calling the code to do the work of fetching the data necessary to fulfil the request (as traditional resolvers do), they serve to build a "field plan" that describes the required actions (or "steps"). The system then combines all of these field plans into an "operation plan", and it can manipulate the steps in this plan — merging, replacing, reorganizing and optimizing — ultimately resulting in a highly optimized plan that minimizes the work that backend services need to do.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.graphile.org/ext/plan-code.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fld592d4u6rg7xrtyy9k9.png" alt="A screenshot showing GraphQL type definitions on the left and 'plan resolvers' on the right; the plan resolvers are between 1 and 3 lines of code each and look similar to traditional resolvers" width="800" height="560"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
Example plan resolvers, similar to the ones that PostGraphile V5 builds internally. Despite their apparent simplicity, they express everything the system needs to know in order to build highly efficient queries against your backend. Note that plan resolvers are entirely synchronous: no data is fetched during planning — the fetching comes later, once the plan has been fully processed and optimized.
&lt;/p&gt;



&lt;p&gt;I saw this stability of the plan resolvers despite major changes to the planning and execution engine as a validation of the core of my idea — the abstraction was right, I just needed to figure out how to build the final engine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And, build it, I did!&lt;/strong&gt; (Eventually…)&lt;/p&gt;

&lt;p&gt;One of the final breakthroughs I had was that piggy–backing off of GraphQL.js' execution model just wasn't going to let me do everything I needed the system to do, at least not as quickly as I wanted it to do it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.graphile.org/ext/flamegraph.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnavv4d8mdnnmm4xzy2p9.png" alt="Flame graph showing about 25% 'Crystal execute', 60% GraphQL.js (synchronous) and 15% Fastify" width="800" height="120"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
A profiling &lt;a href="https://www.brendangregg.com/flamegraphs.html" rel="noopener noreferrer"&gt;flame graph&lt;/a&gt; from Graphile Crystal (a precursor to Grafast) using GraphQL.js' executor (each tick is 1ms, total: 29ms). As we removed more and more responsibilities from GraphQL.js, we ended up only using it for output. Replacing this final responsibility with a custom implementation in Graphile Crystal itself, we reduced execution time for this query down to 15.5ms (effectively removing the majority of the yellow portion of the flame graph).
&lt;/p&gt;



&lt;p&gt;So, rather than continuing to squeeze a declarative holistic execution system inside of a linear execution system, I decided to write my own GraphQL execution engine. Ultimately, this resulted in Gra&lt;em&gt;fast&lt;/em&gt;, the next generation planning and execution engine for GraphQL! You can find more about this and what makes it so exciting, not just for PostGraphile but for the entire GraphQL ecosystem, in this video:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/H26uBe_lLag"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Gra&lt;em&gt;fast&lt;/em&gt; solved all of my issues with look–ahead, and was more powerful and flexible too! It was, and remains to be, a joy to work with. Gra&lt;em&gt;fast&lt;/em&gt; is better than look–ahead in every way I cared about: plans are simpler to write and maintain, easier to read, they execute faster, they are more capable — handling polymorphism and incremental delivery and all these other fun things that GraphQL gives us access to — and the SQL queries that the system built for V5 were so much simpler and easier to read (and faster to execute!) than those in V4.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.graphile.org/ext/v4-query-generation.png" rel="noopener noreferrer"&gt;&lt;br&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjms4g8rae269tyf1cwjo.png" alt="GraphQL query (left) and SQL for that query generated by v4 (right). The SQL on the right is complex and has many levels of nesting." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
A GraphQL query (left), accompanied by the SQL generated by PostGraphile V4 from that query (right). The generated query is tightly coupled with the structure of the GraphQL request and this leads to verbose and overcomplicated SQL.
&lt;/p&gt;



&lt;p&gt;&lt;a href="https://www.graphile.org/ext/v5-query-generation.png" rel="noopener noreferrer"&gt;&lt;br&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp5zij4mlorcvwfwi37ym.png" alt="GraphQL query (left) and SQL for that query generated by v5 (right). The SQL on the right is around one quarter of that generated by V4 and is much easier to read." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
The same GraphQL query as above (left), accompanied by the SQL generated by PostGraphile V5 from that query (right). The SQL is much simpler and faster to execute than that produced by V4; not to mention also much easier to read and understand.
&lt;/p&gt;



&lt;p&gt;But!&lt;/p&gt;

&lt;p&gt;There was a problem.&lt;/p&gt;

&lt;p&gt;A big problem.&lt;/p&gt;

&lt;p&gt;PostGraphile V4 was entirely built on top of the look–ahead engine. Every type, every field, every argument interacts with the look–ahead engine. And I'd relegated the look–ahead engine to the trash! With the look–ahead system removed, almost nothing worked.&lt;/p&gt;

&lt;p&gt;So I set about doing what we're always told not to do: I rebuilt everything. From scratch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And, since I was rebuilding it all anyway, I could solve a few of the other problems that had been bugging me…&lt;/strong&gt; 🤔&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;del&gt;Check back next week for&lt;/del&gt; Next, check out &lt;a href="https://dev.to/graphile/intro-to-postgraphile-v5-part-2-plugins-and-presets-26fe"&gt;Part 2: Plugins and Presets&lt;/a&gt;; and remember: to get your hands on a pre–release version of PostGraphile V5, all you need to do is sponsor Graphile at any tier and then drop us an email or DM! Find out more at &lt;a href="https://graphile.org/sponsor" rel="noopener noreferrer"&gt;graphile.org/sponsor&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>postgraphile</category>
      <category>graphql</category>
      <category>postgres</category>
      <category>grafast</category>
    </item>
    <item>
      <title>How I Made PostGraphile Faster Than Prisma: 1 Year Later</title>
      <dc:creator>Benjie</dc:creator>
      <pubDate>Wed, 22 May 2019 13:59:41 +0000</pubDate>
      <link>https://dev.to/graphile/how-i-made-postgraphile-faster-than-prisma-1-year-later-4ead</link>
      <guid>https://dev.to/graphile/how-i-made-postgraphile-faster-than-prisma-1-year-later-4ead</guid>
      <description>&lt;h3&gt;
  
  
  Thanks, in part, to the incredible performance increases in Node 12
&lt;/h3&gt;

&lt;p&gt;In May last year I released &lt;a href="https://medium.com/graphile/how-i-made-postgraphile-faster-than-prisma-graphql-server-in-8-hours-e66b4c511160" rel="noopener noreferrer"&gt;How I Made PostGraphile Faster Than Prisma In 8 Hours&lt;/a&gt; to debunk the extremely misleading graph Prisma had integrated into their marketing website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F80q9lfspsx8x3kxwkg77.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F80q9lfspsx8x3kxwkg77.gif" width="640" height="360"&gt;&lt;/a&gt;I wish I had the budget to debunk this chart with equivalent pretty design and animation.&lt;/p&gt;

&lt;p&gt;PostGraphile focusses on performance for the kind of GraphQL queries you’d see when building a web application following best practices—single GraphQL queries that pull all the required data for an individual web page. Prisma benchmarked an unrealistically small query (&lt;code&gt;byArtistId&lt;/code&gt;, see below), which effectively meant they were benchmarking the HTTP layer rather than the GraphQL resolution itself. A little friendly competition is good for the ecosystem, and I hadn’t yet optimised the HTTP layer in PostGraphile, so this was good justification to set aside a day later that week to doing some performance work. It didn’t take long for PostGraphile to beat Prisma even at this trivially small query—I do love optimisation!&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-997064259220770816-360" src="https://platform.twitter.com/embed/Tweet.html?id=997064259220770816"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-997064259220770816-360');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=997064259220770816&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Six months later, Prisma let me know they’d taken the graph down, and had improved their own performance significantly. They requested that I re-run the benchmarks. As a &lt;a href="https://www.graphile.org/sponsor/" rel="noopener noreferrer"&gt;crowd-funded open source developer&lt;/a&gt;, it took a while to find more time to allocate to performance and benchmarking work.&lt;/p&gt;

&lt;p&gt;Following &lt;a href="https://www.graphile.org/news/postgraphile-version-4-4/" rel="noopener noreferrer"&gt;the release of PostGraphile 4.4&lt;/a&gt;, and as a celebration of the release of Node 12, I allowed myself to spend some time deep in the developer tools for Node, finding where our performance could be further improved. &lt;code&gt;chrome://inspect&lt;/code&gt; is incredibly useful for this purpose.&lt;/p&gt;

&lt;p&gt;Node 12 itself brought some impressive performance gains, and it also opened wider support for modern JavaScript features, allowing us to tell TypeScript to compile to a newer ECMAScript target and leverage various performance increases from not having to poly-fill expressive syntax. To maintain backwards compatibility, these optimisations are opt-in via the &lt;code&gt;GRAPHILE_TURBO&lt;/code&gt; environmental variable. Node 12 also brought with it a new HTTP parser, &lt;code&gt;llhttp&lt;/code&gt;, which apparently is a little faster also. All in all, this gave us some great performance gains just from changing some compiler flags and using a newer Node.js version!&lt;/p&gt;

&lt;p&gt;In PostGraphile’s codebase itself, there were a few places that we managed to squeeze out some more performance. I’ll release a post soon for Node.js developers explaining exactly what we did (&lt;a href="http://eepurl.com/gfV9LD" rel="noopener noreferrer"&gt;sign up to our mailing list&lt;/a&gt; to be notified about this and other Graphile news), but the main things were to reduce our code’s garbage collection overhead, perform more ahead-of-time computation, and to automatically track and reuse PostgreSQL prepared statements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnzwo1olszhsqk4em9924.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnzwo1olszhsqk4em9924.png" width="800" height="266"&gt;&lt;/a&gt;From ~6:28:33 to ~6:30:18 we ran 200,000 requests against an instrumented instance of PostGraphile, and tracked the memory usage using &lt;a href="https://github.com/nearform/node-clinic" rel="noopener noreferrer"&gt;node-clinic&lt;/a&gt; (which is pretty cool, by the way). This “saw tooth” graph shows where Node periodically runs garbage collection (GC) to free up memory that’s no longer in use.&lt;/p&gt;

&lt;p&gt;Following these optimisations I re-ran the benchmarks, testing the latest version of Prisma (1.32), PostGraphile 4.0.0 running on Node 10, and the alpha of PostGraphile 4.4.1 running on Node 12 with &lt;code&gt;GRAPHILE_TURBO&lt;/code&gt; enabled. The only significant change we made to the benchmarks was to reduce the warmup concurrency (see &lt;code&gt;albums_tracks_genre_all&lt;/code&gt; below for reasoning).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Enough with the story — show us the numbers!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://graphql-bench-visualizer.now.sh/" rel="noopener noreferrer"&gt;last year’s graphs&lt;/a&gt;, the latest version of PostGraphile (labelled &lt;code&gt;postgraphile-next&lt;/code&gt;, which was actually &lt;a href="https://github.com/graphile/postgraphile/releases/tag/v4.0.0-beta.10" rel="noopener noreferrer"&gt;v4.0.0-beta.10&lt;/a&gt;) was in pink. PostGraphile v4.0.0 had a similar performance profile to this version, so we’ve made that pink &lt;a href="https://graphql-bench-visualizer2.now.sh/" rel="noopener noreferrer"&gt;in the new graphs&lt;/a&gt; for reference. We’ve added a new line, in green, for the latest version:&lt;code&gt;postgraphile@alpha&lt;/code&gt; (v4.4.1-alpha.4).&lt;/p&gt;

&lt;p&gt;I also added crosses to the latency charts to indicate when 0.1% or more of the requests failed (and have labelled the crosses with the percentage of failed requests) because this is an important metric that wasn’t previously visible without cross-referencing the relevant “Successful requests” chart. Further, the Y axis has been extended to show a slightly higher range of latencies.&lt;/p&gt;

&lt;p&gt;What follows is a section for each of the 5 queries benchmarked. The benchmark setup is almost exactly the same as last year, so I won’t go into it again (see the “Benchmarking” section from &lt;a href="https://medium.com/graphile/how-i-made-postgraphile-faster-than-prisma-graphql-server-in-8-hours-e66b4c511160" rel="noopener noreferrer"&gt;last year’s post&lt;/a&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  prisma_deeplyNested
&lt;/h4&gt;

&lt;p&gt;This query shows how the various softwares handle a query that touches a number of database tables, relations and columns. Prisma named this request “deeply nested” but it’s not uncommon for a frontend-facing GraphQL API to have to handle a query similar to this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query prisma_deeplyNested {
  allAlbumsList(condition: {artistId: 127}) {
    albumId
    title
    tracksByAlbumIdList {
      trackId
      name
      genreByGenreId { name }
    }
    artistByArtistId {
      albumsByArtistIdList {
        tracksByAlbumIdList {
          mediaTypeByMediaTypeId { name }
          genreByGenreId { name }
        }
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sf0uuzn5r4w0waa0r9o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sf0uuzn5r4w0waa0r9o.png" width="800" height="453"&gt;&lt;/a&gt;This chart shows how many requests per second the various softwares can handle before they start dropping requests (or not meeting the 5s latency cut-off). Prisma have gone from 100rps last year to 225rps — a significant increase. PostGraphile handles higher loads more gracefully now—though we start dropping requests a little after 700rps, even at 800rps we’re only dropping 2.26%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbphrgefgpq2dmwm7divi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbphrgefgpq2dmwm7divi.png" width="800" height="453"&gt;&lt;/a&gt;This 95th percentile latency chart shows how quickly the various softwares respond to requests under different loads. The latest PostGraphile has reduced latency across the board, and still performs well past its peak of 600rps.&lt;/p&gt;

&lt;h4&gt;
  
  
  albums_tracks_genre_all
&lt;/h4&gt;

&lt;p&gt;Last year we had to exclude this query as we didn’t get any results from Prisma and weren’t sure why. This year we figured it out: Prisma had become overwhelmed during the warmup period and could not respond when the main benchmarks started. The solution was to reduce the concurrency during the 5 minute warmup period from 100rps to 10rps (you can read about why warmup is necessary in last year’s post).&lt;/p&gt;

&lt;p&gt;This query shows fetching all the rows from a particular collection in the database, and some of the related records. Typically a frontend GraphQL request like this should have pagination at the root level (e.g. limiting to 50 albums at a time), but since there’s only 347 rows in the albums table it’s not too bad. This query better represents a GraphQL query you might make from your backend rather than one from your web frontend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query albums_tracks_genre_all {
  allAlbumsList {
    albumId
    title
    tracksByAlbumIdList {
      trackId
      name
      genreByGenreId {
        name
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0k0mheknfgx7w8mehnhu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0k0mheknfgx7w8mehnhu.png" width="800" height="453"&gt;&lt;/a&gt;PostGraphile improves from 70rps to 80rps without dropping any requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdfjj5u6lh5nd8r5gqji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdfjj5u6lh5nd8r5gqji.png" width="800" height="453"&gt;&lt;/a&gt;Even at 80rps, PostGraphile handles 95% of requests in under 250ms. The latest postgraphile@alpha shows a significant reduction in latency and increase in throughput.&lt;/p&gt;

&lt;h4&gt;
  
  
  albums_tracks_genre_some
&lt;/h4&gt;

&lt;p&gt;This query is almost identical to the previous one, except it reduces the number of results (from 347 down to just 3) by filtering against a specific artist. This is a reasonably good example of a simple frontend GraphQL query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query albums_tracks_genre_some {
  allAlbumsList(condition: {artistId: 127}) {
    artistId
    title
    tracksByAlbumIdList {
      trackId
      name
      genreByGenreId {
        name
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zuffi8ewwbtud5zeg03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zuffi8ewwbtud5zeg03.png" width="800" height="453"&gt;&lt;/a&gt;Prisma improved significantly—from 300rps last year to 800rps this year. PostGraphile increased from 1500rps to 1700rps, and handles going over its maximum more gracefully: at 1800rps PostGraphile drops only 0.7% of incoming requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fom1qbtyne7vkyp0ij00v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fom1qbtyne7vkyp0ij00v.png" width="800" height="453"&gt;&lt;/a&gt;PostGraphile’s latency is lower than ever, serving 95% of requests at 1700rps in under 50ms.&lt;/p&gt;

&lt;h4&gt;
  
  
  byArtistId
&lt;/h4&gt;

&lt;p&gt;This query is extremely simple and light, just requesting two fields from a single row in the database. It’s rare that you’d have a GraphQL request this simple in the web frontend of a non-trivial application—it shows more about the underlying performance of the HTTP layer than the GraphQL resolution itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query artistByArtistId {
  artistByArtistId(artistId: 3) {
    artistId
    name
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3h5gwzgks7scwf64yxb5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3h5gwzgks7scwf64yxb5.png" width="800" height="453"&gt;&lt;/a&gt;This graph looks surprisingly similar to last years, except everything has moved to the right! PostGraphile can now handle an impressive 3700rps (vs last year’s 3000rps) without dropping any requests, and gets to 4000rps (vs last years 3200rps) whilst dropping only 0.8% of requests. Prisma have improved too, from 2750rps without dropping a request to 3600rps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuv867ea3l0dbbn97sdox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuv867ea3l0dbbn97sdox.png" width="800" height="453"&gt;&lt;/a&gt;The crosses indicating failure percentages really help to interpret the latency results here; after 3000rps Prisma manages to achieve marginally lower latency than PostGraphile for a short while until they start dropping requests at 3700rps. This is likely due to the differences in how Scala (which runs on the JVM) and Node.js handle garbage collection.&lt;/p&gt;

&lt;h4&gt;
  
  
  tracks_media_first_20
&lt;/h4&gt;

&lt;p&gt;Included for completeness, this query requests 2 columns from 20 rows in a single database table—like a slightly heavier version of byArtistId. GraphQL requests from webpages are rarely this simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query tracks_media_first_20 {
  allTracksList(first: 20) {
    trackId
    name
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ugmw9lkb47g8etw4vsf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ugmw9lkb47g8etw4vsf.png" width="800" height="453"&gt;&lt;/a&gt;Prisma have improved from 2000rps last year to 3000rps this year. PostGraphile increases its lead at 3500rps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filrjng50xlu1vhestnnn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filrjng50xlu1vhestnnn.png" width="800" height="453"&gt;&lt;/a&gt;Again, this graph shows the difference in garbage collection, HTTP overhead, and other related costs in Node.js vs Scala, with Node achieving greater throughput but with marginally higher latency at high concurrency.&lt;br&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  Is speed really that important?
&lt;/h4&gt;

&lt;p&gt;Yes and no. I do optimisations because it’s a fun challenge to see how far I can push the computer in an interpreted language without having to make my code too messy. PostGraphile’s users will now benefit from faster performance and happier endusers just from updating to the latest version — they don’t need to change any of their code at all. I think that’s really cool✨&lt;/p&gt;

&lt;p&gt;But performance isn’t everything—one of the things we focus on at PostGraphile is extensibility. Our job isn’t to simply convert your database from SQL to GraphQL. Our job is to help you build your ideal GraphQL API as quickly as possible. To help with that, we do as much of the boilerplate for you as we can, but then we give you ways to add to, customise and otherwise make the GraphQL schema your own. We fundamentally do not believe that our job is to expose all the functionality of the database to your end users; instead we believe that we should allow you to leverage the functionality of the database to build the GraphQL API that your frontend developers need, without them having to worry about the complexities of joins, subqueries, common-table expressions, &lt;code&gt;ON CONFLICT DO UPDATE&lt;/code&gt;, indexes, SQL query optimisation, and other such things. Despite PostGraphile’s extensibility and flexibility it achieves incredibly good performance, thanks in part to the choice of Node.js as the development platform.&lt;/p&gt;

&lt;h4&gt;
  
  
  So what’s next?
&lt;/h4&gt;

&lt;p&gt;You can take the new PostGraphile for a spin right now with &lt;code&gt;yarn install postgraphile@alpha&lt;/code&gt;. It passes all the tests, but hasn’t been fully vetted by the community yet, hence the “alpha” label—if you try it out, drop us a line &lt;a href="http://discord.gg/graphile" rel="noopener noreferrer"&gt;on our Discord chat&lt;/a&gt; to let us know how you got on!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;yarn install postgraphile@alpha&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you appreciate our work, please &lt;a href="https://www.graphile.org/sponsor/" rel="noopener noreferrer"&gt;sponsor us&lt;/a&gt;—we’re hugely thankful to our Patreon sponsors who help us to keep moving things forward.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you appreciate our work, please &lt;a href="https://www.graphile.org/sponsor/" rel="noopener noreferrer"&gt;sponsor us&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks for reading, I’ll be releasing another post soon on the Node.js performance optimisations that I used to make this possible—&lt;a href="http://eepurl.com/gfV9LD" rel="noopener noreferrer"&gt;sign up to our mailing list&lt;/a&gt; to be notified about this and other Graphile news.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://eepurl.com/gfV9LD" rel="noopener noreferrer"&gt;Sign up to our mailing list&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>graphql</category>
      <category>sql</category>
      <category>node</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
