Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ tags: [0.1]
hide_table_of_contents: true
---

Gra*fast* 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. It‘s backwards compatible, so you can adopt it incrementally within your existing schema and it‘s finally ready to try with [the `grafast` module on npm](https://www.npmjs.com/package/grafast); or check out [the source code on GitHub](https://github.com/graphile/crystal/tree/main/grafast/grafast)!
import styles from "@site/src/css/common.module.css";

<p className={styles.intro}>

Gra*fast* is finally here &mdash; 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. It’s backwards compatible, so you can adopt it incrementally within your existing schema and it’s finally ready to try with [the `grafast` module on npm](https://www.npmjs.com/package/grafast); or check out [the source code on GitHub](https://github.com/graphile/crystal/tree/main/grafast/grafast)!

</p>

<figure>
<iframe
Expand All @@ -33,21 +39,23 @@ Gra*fast* is finally here &mdash; a new holistic execution engine for GraphQL. I

## Gra*fast* Working Group

There&lsquo;s still decisions to be made and edges to be smoothed before Gra*fast* can become a specification that can be implemented in any language. If the potential of this technology is interesting to you, please [join the Gra*fast* working group](https://github.com/grafast/wg) and get involved. We all deserve our future of easy GraphQL execution efficiency!
Theres still decisions to be made and edges to be smoothed before Gra*fast* can become a specification that can be implemented in any language. If the potential of this technology is interesting to you, please [join the Gra*fast* working group](https://github.com/grafast/wg) and get involved. We all deserve our future of easy GraphQL execution efficiency!

If you don&lsquo;t have time to watch the video above, here&lsquo;s a little about Gra*fast*:
<!-- truncate-->

## &ldquo;GraphQL&lsquo;s execution model is wrong for most servers&rdquo;
If you don’t have time to watch the video above, here’s a little about Gra*fast*:

## &ldquo;GraphQL’s execution model is wrong for most servers&rdquo;

GraphQL is a declarative language; the requests specify everything that the client is asking for up&ndash;front.

But the resolver&ndash;based execution model **_obfuscates_** this knowledge &mdash; when implemented naively, resolvers can very quickly result in serious performance issues; and even when implemented well they leave a lot to be desired.

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

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

## &ldquo;Step aside resolvers! There&lsquo;s a new way to execute GraphQL&rdquo;
## &ldquo;Step aside resolvers! Theres a new way to execute GraphQL&rdquo;

<figure>

Expand All @@ -62,7 +70,7 @@ Grafast calls &ldquo;plan resolvers&rdquo; to determine the requirements for eac

Gra*fast* 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, Gra*fast* 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&ndash;based execution model unless one puts in herculean effort (and a little sorcery 😉).

Gra*fast*, like GraphQL, is not specific to any particular technology stack, business logic shape or data storage layer. It doesn&lsquo;t care if you&lsquo;re using relational databases, document stores, ORMs, HTTP APIs, file systems or _[carrier pigeons](https://datatracker.ietf.org/doc/html/rfc1149)_. Any valid GraphQL schema can be implemented with Gra*fast*, and a Gra*fast* schema can query any data source, business logic or service.
Gra*fast*, like GraphQL, is not specific to any particular technology stack, business logic shape or data storage layer. It doesnt care if youre using relational databases, document stores, ORMs, HTTP APIs, file systems or _[carrier pigeons](https://datatracker.ietf.org/doc/html/rfc1149)_. Any valid GraphQL schema can be implemented with Gra*fast*, and a Gra*fast* schema can query any data source, business logic or service.

Though it supports traditional resolvers, Gra*fast* encourages developers to use &ldquo;plan resolvers&rdquo;: small functions similar to resolvers but which describe the required data, rather than actually fetching it.

Expand All @@ -88,23 +96,24 @@ This greater understanding of the needs of the GraphQL requests unlocks entire n
<blockquote class="twitter-tweet" data-conversation="none" data-theme="light">
<p lang="en" dir="ltr">
<strong>
Probably worth looking into the work{" "}
<a href="https://twitter.com/Benjie?ref_src=twsrc%5Etfw">@Benjie</a> is
doing with Grafast as well. Feels like the missing substrate in the GraphQL
world.
Probably worth looking into the work{" "}
<a href="https://twitter.com/Benjie?ref_src=twsrc%5Etfw">@Benjie</a> is
doing with Grafast as well. Feels like the missing substrate in the
GraphQL world.
</strong>
</p>
&mdash; Sean Grove (@sgrove){" "}
<a href="https://twitter.com/sgrove/status/1696572548803162477?ref_src=twsrc%5Etfw">
August 29, 2023
</a>
</blockquote> <script
</blockquote>
<script
async
src="https://platform.twitter.com/widgets.js"
charset="utf-8"
></script>

Gra*fast* already works and some of my [sponsors](https://graphile.org/sponsors) are already running it in production. You can try it out today by following the guide at [grafast.org](https://grafast.org). All that&lsquo;s left for me to say now is, if the potential of this new technology is interesting, then please:
Gra*fast* already works and some of my [sponsors](https://graphile.org/sponsors) are already running it in production. You can try it out today by following the guide at [grafast.org](https://grafast.org). All thats left for me to say now is, if the potential of this new technology is interesting, then please:

## Help shape the future on 24th October and join the [Gra*fast* working group](https://github.com/grafast/wg)!

Expand All @@ -113,5 +122,3 @@ Gra*fast* already works and some of my [sponsors](https://graphile.org/sponsors)
[![A cartoon graphic of superheroes looking over their city at sunset. The text reads "Get involved" and there is a link to the Grafast working group hosted on GitHub](../static/img/news/2023-10-13-get-involved.png)](https://github.com/grafast/wg)

</figure>

<!--truncate-->
122 changes: 122 additions & 0 deletions grafast/website/news/2025-03-24-grafast-0.1-beta.21.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
---
title: "Major Grafast beta released: Three down, one to go!"
description:
"This release contains more than 3 months of work, and is a major step towards
release readiness."
slug: 2025-03-24-grafast-0.1-beta.21
authors:
- name: Benjie
title: Inventor of Grafast
url: https://github.com/Benjie
image_url: https://github.com/Benjie.png
tags: [0.1]
hide_table_of_contents: true
---

import styles from "@site/src/css/common.module.css";

<p className={styles.intro}>

In the first Gra<em>fast</em> Working Group, we outlined 4 <em>major</em> issues in Gra<em>fast</em>
that needed to be addressed before we could think about general release. With
this release, 3 of these are now complete!

- ✅⤵️ Global dependencies - solved via "unary" steps
- ✅⤵️ Early exit - solved via "flags"
- ✅🎉 **Eradicating eval - this release!**
- 🤔🔜 Polymorphism

We’re proud to announce that the third of these, eradicating eval, is now
addressed with the launch of `[email protected]`, and the approach has been
fully adopted and tested via incorporation into `[email protected]`.

</p>

## Input evaluation moved to runtime

Since the beginning, Gra*fast* 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*fast*’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.

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
`applyPlan` or `inputPlan` 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.

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

<!-- truncate-->

### What does this mean for my codebase?

Hopefully good things! Please update to the latest `grafast@beta` and for most
users everything should work as before, only better.

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 [in the
chat](https://discord.gg/graphile) — 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.

#### Change `fieldArgs.get` to `fieldArgs.getRaw`

Because we’ve removed `inputPlan`, the `fieldArgs.get(key)` method is no more;
instead use `fieldArgs.getRaw(key)` 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*fast* schema.

#### Converting `applyPlan` and `inputPlan`

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

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*fast* 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 `applyPlan` to `apply`, and `inputPlan` to `baked`.
From there, your code might just work straight away, or it might need some more
small tweaks (e.g. `fieldArgs` is no longer present, it’s been replaced with
simply the runtime value of the current field).

#### No more `$step.eval*()`

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?

If you were, a new `.apply()` 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 `ORDER BY` clause in an SQL query based on a variable argument.
You may want to adopt a similar pattern in your own step classes.

#### ExecutableStep renamed to Step

This one is more cosmetic…

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

_We have kept an <code>ExecutableStep</code> export for backwards
compatibility._
11 changes: 11 additions & 0 deletions grafast/website/src/css/common.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,14 @@
background: inherit;
color: var(--ifm-color-primary);
}

.intro {
color: var(--ifm-color-primary-darkest);
font-style: italic;
font-size: 1.25rem;
}

.intro li,
code {
font-style: normal;
}