Library / SDK
Escape-Technologies/graphql-armor avatar
Escape-Technologies/graphql-armor

graphql-armor is a GraphQL security middleware layer, and the README leaves the actual limits to the docs site

🛡️ The missing GraphQL security security layer for Apollo GraphQL and Yoga / Envelop servers 🛡️

588 stars52 forksTypeScriptMIT

At a glance

What is it?
Escape-Technologies/graphql-armor packages GraphQL hardening as middleware for Apollo Server and GraphQL Yoga, with a plugin route through Envelop for a dozen other engines, and ships it as a TypeScript monorepo of preconstruct built packages. It is MIT licensed, and the repository documentation deliberately stops short of listing which protections are enabled by default.
Who is it for?
Use graphql-armor if you run Apollo Server or GraphQL Yoga and want GraphQL specific hardening as middleware rather than as code you write and maintain in every service. Do not adopt it on the strength of the repository README alone, because it does not enumerate the protections it applies, and the commercial product from the same vendor sits behind a sales conversation.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

GraphQL hardening as middleware rather than as your code

GraphQL Armor is a security middleware for GraphQL server engines, described as dead-simple yet highly customizable, and the repository is billed as the missing GraphQL security layer for Apollo GraphQL and Yoga and Envelop servers.

The problem it addresses is specific to GraphQL. A REST API has a small, fixed set of endpoints, and the exposure is a function of how many of them you expose. A GraphQL server typically exposes one endpoint and lets the client describe the query it wants, which means the attack surface is defined by the schema and the resolver tree rather than by a route table. A client can ask for a deeply nested selection, ask for a field that fans out into many subrequests, or ask for a huge amount of data in one round trip, and the server has to refuse.

Doing that by hand means every service in the organisation writes the same depth check, the same complexity estimate and the same blocking logic, usually slightly differently. Middleware is the shape that removes that duplication, and the compatibility list is the reason to pick this one over an in-house implementation.

The audience is therefore teams running GraphQL in production who want the hardening to be a dependency rather than a project, and the commercial note in the README points at the same vendor's enterprise offering for the enterprise level, which is worth noting before you commit to a library whose vendor also sells a product in the same space.

Two engines directly, a dozen more through Envelop

The engine support list is the most concrete thing the documentation gives you, and it is split in two tiers.

Apollo Server and GraphQL Yoga are supported directly. Everything else goes through the Envelop plugin system, and the list is long: GraphQL-Helix, Node.js HTTP, GraphQL-Helix with @defer and @stream, GraphQL-WS, GraphQL-SSE, Azure Functions, Cloudflare Workers, Google Cloud Functions, Lambda AWS, type-graphql, nexus and express-graphql. The documentation points at the Envelop integrations page for more detail on compatibility.

The distinction matters more than the list length. Apollo Server and Yoga are integrated at the engine level, so the middleware sees the request in the shape those engines provide. The Envelop route is a plugin, which means the protections are applied in the Envelop pipeline rather than in the server's own request handling, and the same plugin works across every engine Envelop supports. That is why a serverless function, a WebSocket transport and a plain Node HTTP server all appear in the same list.

Two of the entries also tell you the project cares about the streaming case. GraphQL-Helix appears twice, once plain and once with @defer and @stream, and there are separate entries for the WebSocket and server-sent-events transports. Incremental delivery changes how a response is produced over time, and a security layer that only understood a single completed response would be blind to part of it.

The examples directory backs the claim, with working projects for apollo, yoga and nestjs, so you can see the wiring in a real server rather than only in a snippet.

Installing it is one command per package manager

The installation section is short, which is appropriate for a package that is meant to be added to an existing project rather than deployed on its own.

bash
# npm
npm install -S @escape.tech/graphql-armor

# yarn
yarn add @escape.tech/graphql-armor

The scoped package name is the thing to note. It is published under @escape.tech, the same scope as the vendor's other packages, and the release list also shows a separate package, @escape.tech/graphql-armor-max-depth, at version 2.4.2, which suggests the protections are distributed as separate plugins rather than only as one monolith.

That is a meaningful design choice for a security library. If depth limiting and the other checks are separate packages, a team can compose the profile it needs, and the release version of each package moves independently, which the release list shows: graphql-armor 3.2.0 was published on 2025-12-29 and graphql-armor-max-depth 2.4.2 on 2025-08-22, so the two version lines do not move together.

So a dependency pin on the main package does not pin the behaviour of the depth limit. If you depend on both, you need to manage both version lines, and the monorepo layout makes that a per plugin decision.

The getting started page is at escape.tech/graphql-armor/docs/getting-started, and the README links it directly rather than duplicating the configuration, which is a reasonable choice for a project with this many engine combinations.

A preconstruct monorepo with plugins, docs services and examples

The repository is a yarn workspaces monorepo, and the package layout is where the architecture is visible.

The workspaces field covers examples/*, packages/*, packages/plugins/* and services/*. That means the published libraries live under packages/, with the individual protections under packages/plugins/, the documentation site is a service, and the runnable examples are separate workspaces. The root package is private, named @escape.tech/graphql-armor-monorepo, and the npm scope is the same @escape.tech one used by the published packages.

The build is done with preconstruct. The build script runs preconstruct build, and there is a parallel build:yarn script that uses yarn workspaces foreach to run the build in each workspace. Preconstruct is a tool for building several packages that share a source layout, which is the right fit here, because the main package and the plugin packages are versions of the same codebase at different entry points.

The rest of the tooling is conventional and well chosen. Jest runs the tests, with a separate test:ci script that adds coverage. The release process uses changesets, with a .changeset/ directory in the tree and a release script that publishes through changeset publish, and commitlint with an angular configuration for commit message linting, enforced through git hooks in the hooks/ directory. Renovate is configured for dependency updates, and prettier with a sort-imports plugin handles formatting.

For a security library, the release tooling is the part worth appreciating. Changesets means each package can be versioned and published independently with a written changelog entry, which matters when a security fix lands in one plugin and you need to know exactly which version of which package carries it.

The lint script that keeps two READMEs identical

One script in the package metadata is worth reading on its own, because it says something about how the project is maintained.

The lint script is prettier --check '**/*.{ts,js}' followed by a diff between README.md and packages/graphql-armor/README.md. In other words, the lint step fails if the root README and the README inside the main package have drifted apart.

That is a small automation with a real effect. The root README is what people read on GitHub, and the package README is what people read on npm, and the two are published to two audiences that do not always see the same text. A project that cannot keep them in sync ends up with one of them going stale, and the stale one is usually the one inside the package, where a consumer looking at the registry cannot tell it is out of date.

The repository also carries SECURITY.md, CODE_OF_CONDUCT.md, a CONTRIBUTING.md, and the .mookme.json file used by the docs tooling, plus an examples directory with apollo, nestjs and yoga projects.

The developer setup is documented too, and it is a monorepo setup rather than a one package setup: clone over SSH, then run the install-dev.sh script, which is what the README says to do before contributing.

bash
git clone [email protected]:Escape-Technologies/graphql-armor.git
cd graphql-armor
bash ./install-dev.sh

The project uses yarn as its package manager and the classic yarn workspaces setup, and the README asks people to read that documentation and to open issues if they hit problems while developing.

What the repository README does not tell you

The most important gap in this documentation is the absence of the thing most adopters need: a list of the protections and their defaults.

The README says the middleware is highly customizable, and it names a separate max depth package, but it does not enumerate the checks it performs, which are on by default, what the limits are, how a rejected query is reported, or whether the limits are per query, per depth, or per complexity. That information lives at the documentation site, which the README links, and the documentation is the source of truth for the configuration.

That arrangement is defensible for a project with a documentation site and a commercial product attached, and it keeps the README short. It does mean the repository alone is not enough to make an adoption decision, which is worth stating plainly for anyone evaluating it on GitHub.

The second gap is the behaviour on rejection. A depth or complexity limit that returns a generic internal server error is a bad experience, and one that returns a detailed explanation of the limit is arguably an information leak about your schema. The documentation site is where that decision is described, and it is worth reading before you enable the protections on a public endpoint.

The third is what the middleware does not cover. GraphQL specific limits are one layer, and a GraphQL server also has authentication, authorisation, persisted queries, cost analysis, and rate limiting, none of which are in scope for a package described as a GraphQL security layer. The commercial offer from the same vendor sits at the enterprise level, which suggests the boundary between the open middleware and the paid product is where that wider scope lives.

So the sensible way to use this repository is as the entry point to the documentation, not as the documentation itself.

MIT terms, an active repository, and a commercial layer above it

The licence is MIT, so the middleware can be used inside a commercial product without a licensing negotiation, and the primary language is TypeScript with the repository on the main branch.

The release history shows a project that is still moving. The published versions are @escape.tech/graphql-armor 3.2.0 from 2025-12-29, 3.1.7 from 2025-08-22, and @escape.tech/graphql-armor-max-depth 2.4.2 from 2025-08-22. The repository is not archived and the last push was on 2026-10-22, so work continues on main between releases.

That gap between the last push and the last tag is the normal shape of a monorepo with changesets, where a change lands in the repository and the version bump follows. It does mean the main branch is not the same thing as a published release, so if you pin versions you pin a specific combination of packages rather than a commit.

The commercial dimension is stated plainly in the README, which points at Escape's website for securing GraphQL APIs at the enterprise level, and ends with a hiring note. A vendor that ships an MIT library and sells an enterprise product around it is a common and reasonable arrangement, but it is worth knowing which part of the roadmap you are depending on.

For a team evaluating this, the concrete questions are short. Which plugins do you actually need, what are their default limits, what happens to a query that exceeds them, and does the version you pin pull the plugin versions you expect. The first two are answered in the documentation, the third is the thing to test, and the fourth is a dependency management exercise with a monorepo's worth of packages to check.

Editorial conclusion

Use graphql-armor if you run Apollo Server or GraphQL Yoga and want GraphQL specific hardening as middleware rather than as code you write and maintain in every service. Do not adopt it on the strength of the repository README alone, because it does not enumerate the protections it applies, and the commercial product from the same vendor sits behind a sales conversation. Before you enable it in production, read the getting started documentation, decide which plugins you want rather than accepting a default profile, and confirm the behaviour of your own queries under the configured limits, because a depth limit that is wrong for your schema is an outage.

Frequently asked questions

What is GraphQL Armor?

It is a security middleware for GraphQL server engines, published as @escape.tech/graphql-armor and described as dead-simple yet highly customizable. It is MIT licensed and written in TypeScript.

Which GraphQL servers does GraphQL Armor support?

Apollo Server and GraphQL Yoga are supported directly. GraphQL-Helix, Node.js HTTP, GraphQL-Helix with @defer and @stream, GraphQL-WS, GraphQL-SSE, Azure Functions, Cloudflare Workers, Google Cloud Functions, Lambda AWS, type-graphql, nexus and express-graphql are supported through the Envelop plugin system.

How do I install GraphQL Armor?

With npm install -S @escape.tech/graphql-armor, or yarn add @escape.tech/graphql-armor. The getting started documentation is linked from the repository README at escape.tech/graphql-armor/docs/getting-started.

Does GraphQL Armor ship as one package or several?

The release list shows separate packages, including @escape.tech/graphql-armor and @escape.tech/graphql-armor-max-depth, and the monorepo has a packages/plugins/ workspace, which suggests the protections are distributed as individual plugins that can be composed.

How do I set up the GraphQL Armor project for development?

Clone the repository over SSH, enter the directory and run bash ./install-dev.sh. The project uses yarn as its package manager with the yarn workspaces monorepo setup, and the contributing guide is linked from the README.

How are GraphQL Armor releases published?

With changesets. The repository has a .changeset/ directory, the release script runs changeset publish, and commitlint with git hooks enforces the commit message format. The main package was last published as 3.2.0 on 2025-12-29.

Official sources

  1. Escape-Technologies/graphql-armor on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/escape-technologies-graphql-armor.svg)](https://hysenlabs.com/projects/escape-technologies-graphql-armor)

Was this useful?