{"id":13727298,"url":"https://github.com/ravangen/graphql-rate-limit","last_synced_at":"2026-01-21T03:30:38.673Z","repository":{"id":34049651,"uuid":"152520045","full_name":"ravangen/graphql-rate-limit","owner":"ravangen","description":"🚦 Fixed window rate limiting middleware for GraphQL. Use to limit repeated requests to queries and mutations.","archived":false,"fork":false,"pushed_at":"2026-01-19T21:51:46.000Z","size":2567,"stargazers_count":320,"open_issues_count":15,"forks_count":13,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-20T04:19:47.514Z","etag":null,"topics":["graphql","graphql-directive","javascript","nodejs","rate-limiter","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/graphql-rate-limit-directive","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ravangen.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-10-11T02:39:02.000Z","updated_at":"2025-10-27T13:43:46.000Z","dependencies_parsed_at":"2023-02-13T01:31:32.343Z","dependency_job_id":"8c389843-7dcd-427f-a8a3-21df77a8afa6","html_url":"https://github.com/ravangen/graphql-rate-limit","commit_stats":{"total_commits":429,"total_committers":7,"mean_commits":"61.285714285714285","dds":0.4638694638694638,"last_synced_commit":"afe131ee7f82f08c2e567699576c1481b6bf9a3c"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ravangen/graphql-rate-limit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravangen%2Fgraphql-rate-limit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravangen%2Fgraphql-rate-limit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravangen%2Fgraphql-rate-limit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravangen%2Fgraphql-rate-limit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ravangen","download_url":"https://codeload.github.com/ravangen/graphql-rate-limit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravangen%2Fgraphql-rate-limit/sbom","scorecard":{"id":762912,"data":{"date":"2025-08-11","repo":{"name":"github.com/ravangen/graphql-rate-limit","commit":"afe131ee7f82f08c2e567699576c1481b6bf9a3c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/3 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"12 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-rv95-896h-c2vc","Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx","Warn: Project is vulnerable to: GHSA-9pv7-vfvm-6vr7","Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j","Warn: Project is vulnerable to: GHSA-rhx6-c78j-4q9w","Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg","Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p","Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-xffm-g5w8-qvg7","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T23:53:02.178Z","repository_id":34049651,"created_at":"2025-08-22T23:53:02.178Z","updated_at":"2025-08-22T23:53:02.178Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28624506,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T02:47:06.670Z","status":"ssl_error","status_checked_at":"2026-01-21T02:45:44.886Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["graphql","graphql-directive","javascript","nodejs","rate-limiter","typescript"],"created_at":"2024-08-03T01:03:48.699Z","updated_at":"2026-01-21T03:30:38.638Z","avatar_url":"https://github.com/ravangen.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# GraphQL Rate Limit\n\n[![CircleCI](https://img.shields.io/circleci/project/github/ravangen/graphql-rate-limit/master.svg?style=popout)](https://circleci.com/gh/ravangen/graphql-rate-limit)\n[![Codecov](https://img.shields.io/codecov/c/github/ravangen/graphql-rate-limit.svg?style=popout)](https://codecov.io/gh/ravangen/graphql-rate-limit)\n[![npm Version](https://img.shields.io/npm/v/graphql-rate-limit-directive.svg?style=popout)](https://www.npmjs.com/package/graphql-rate-limit-directive)\n[![npm Downloads](https://img.shields.io/npm/dm/graphql-rate-limit-directive.svg?style=popout)](https://www.npmjs.com/package/graphql-rate-limit-directive)\n[![Dependency Status](https://img.shields.io/librariesio/release/npm/graphql-rate-limit-directive)](https://github.com/ravangen/graphql-rate-limit/pulls/app%2Frenovate)\n\nFixed window rate limiting directive for GraphQL. Use to limit repeated requests to queries and mutations.\n\n## Features\n\n- 👨‍💻 **Identification**: Distinguish requests using resolver data\n- 🎯 [**Per-Object or Per-Field**](#step-3-attach-directive-to-field-or-object): Limit by objects and specific fields\n- 📦 [**Storage**](#limiterclass): Supports multiple data store choices (_Redis_, process _Memory_, ...)\n- ♾️ [**Throttles**](examples/multiple): Define any number of limits per field\n- ⚙️ **Extensions**: Granular customization of [field](examples/field-extension/) and [response](examples/response-extension/) behaviour\n- 😍 **TypeScript**: Written in and exports type definitions\n\n## Install\n\n```bash\nyarn add graphql-rate-limit-directive\n```\n\nYou must also install peer dependencies:\n\n```bash\nyarn add rate-limiter-flexible graphql @graphql-tools/utils\n```\n\n## How it works\n\nGraphQL Rate Limit wraps resolvers, ensuring an action is permitted before it is invoked. A client is allocated a maximum of `n` operations for every fixed size time window. Once the client has performed `n` operations, they must wait.\n\n## Setup\n\n### Step 1: Define directive type definition and transformer\n\nImport `rateLimitDirective` and configure behaviour of directive (see [options](#ratelimitdirectiveoptions)).\n\n```javascript\nconst { rateLimitDirective } = require('graphql-rate-limit-directive');\n\nconst { rateLimitDirectiveTypeDefs, rateLimitDirectiveTransformer } = rateLimitDirective();\n```\n\n### Step 2: Add directive to schema\n\nInclude `rateLimitDirectiveTypeDefs` as part of the schema's type definitions.\n\nTransform schema with `rateLimitDirectiveTransformer` to apply implementation of directive.\n\n```javascript\nconst { makeExecutableSchema } = require('@graphql-tools/schema');\n\nlet schema = makeExecutableSchema({\n  typeDefs: [\n    rateLimitDirectiveTypeDefs,\n    /* plus any existing type definitions */\n  ],\n  /* ... */\n});\n\nschema = rateLimitDirectiveTransformer(schema);\n```\n\n### Step 3: Attach directive to field or object\n\nAttach `@rateLimit` directive where desired. Argument `limit` is number of allow operations per duration. Argument `duration` is the length of the fixed window (in seconds).\n\n```graphql\n# Apply rate limiting to all fields of 'Query'\n# Allow at most 60 queries per field within a minute\ntype Query @rateLimit(limit: 60, duration: 60) {\n  ...\n}\n```\n\n#### Overrides\n\nWhen the directive is applied to a object, it rate limits each of its fields. A rate limit on a field will override a limit imposed by its parent type.\n\n```graphql\n# Apply default rate limiting to all fields of 'Query'\ntype Query @rateLimit(limit: 60, duration: 60) {\n  books: [Book!]\n\n  authors: [Author!]\n\n  # Override behaviour imposed from 'Query' object on this field to have different limit\n  quote: String @rateLimit(limit: 1, duration: 60)\n}\n```\n\n## Example\n\nAdditional, advanced examples are available in the [examples](examples) folder:\n\n- [Context](examples/context): isolating operations between users\n- [Points](examples/points): customize the cost of a field resolution\n- [Redis](examples/redis): share state in a distrubuted environment\n- [Multiple](examples/multiple): applying multiple rate limits on the same field\n- [onLimit Error](examples/onlimit-error): custom error raised\n- [onLimit Object](examples/onlimit-object): custom result instead of default resolution\n- [Field Extension](examples/field-extension): override behaviour per field using extensions\n- [Response Extension](examples/response-extension): rate limit details in response extension\n\n```javascript\nconst { makeExecutableSchema } = require('@graphql-tools/schema');\nconst { ApolloServer } = require('apollo-server');\nconst { ApolloServerPluginLandingPageGraphQLPlayground } = require('apollo-server-core');\nconst { rateLimitDirective } = require('graphql-rate-limit-directive');\n\nconst { rateLimitDirectiveTypeDefs, rateLimitDirectiveTransformer } = rateLimitDirective();\n\nconst resolvers = {\n  Query: {\n    books: () =\u003e [\n      {\n        title: 'A Game of Thrones',\n        author: 'George R. R. Martin',\n      },\n      {\n        title: 'The Hobbit',\n        author: 'J. R. R. Tolkien',\n      },\n    ],\n    quote: () =\u003e\n      'The future is something which everyone reaches at the rate of sixty minutes an hour, whatever he does, whoever he is. ― C.S. Lewis',\n  },\n};\nlet schema = makeExecutableSchema({\n  typeDefs: [\n    rateLimitDirectiveTypeDefs,\n    `# Apply default rate limiting to all fields of 'Query'\n    type Query @rateLimit(limit: 1, duration: 15) {\n      books: [Book!]\n\n      # Override behaviour imposed from 'Query' object on this field to have a custom limit\n      quote: String @rateLimit(limit: 1)\n    }\n\n    type Book {\n      # For each 'Book' where this field is requested, apply a rate limit\n      title: String @rateLimit(limit: 72000, duration: 3600)\n\n      # No limits are applied\n      author: String\n    }`,\n  ],\n  resolvers,\n});\nschema = rateLimitDirectiveTransformer(schema);\n\nconst server = new ApolloServer({\n  schema,\n  plugins: [\n    ApolloServerPluginLandingPageGraphQLPlayground(),\n  ]\n});\nserver.listen().then(({ url }) =\u003e {\n  console.log(`🚀  Server ready at ${url}`);\n});\n```\n\n## API\n\n### `rateLimitDirective(options)`\n\n\u003e Create an implementation of a rate limit directive.\n\nIt is common to specify at least [`keyGenerator`](#keyGenerator) and [`limiterClass`](#limiterClass) as part of `options`.\n\nReturns an object containing:\n- `rateLimitDirectiveTypeDefs`: Schema Definition Language (SDL) representation of the directive.\n- `rateLimitDirectiveTransformer`: Function to apply the directive's logic to the provided schema.\n\n#### `name`\n\n\u003e Name of the directive.\n\nOverride the name of the directive, defaults to `rateLimit`.\n\n#### `defaultLimit`\n\n\u003e Default value for argument limit.\n\nOverride the directive's `limit` argument's default value, defaults to `60`.\n\n#### `defaultDuration`\n\n\u003e Default value for argument duration.\n\nOverride the directive's `duration` argument's default value, defaults to `60`.\n\n#### `keyGenerator`\n\n\u003e Constructs a key to represent an operation on a field.\n\nA key is generated to identify each request for each field being rate limited. To ensure isolation, the key is recommended to be unique per field. Supports both synchronous and asynchronous functions.\n\nBy default, it does _not_ provide user or client independent rate limiting. See [`defaultKeyGenerator`](#defaultkeygeneratordirectiveargs-obj-args-context-info) and [context example](examples/context).\n\n**WARNING**: Inside a generator function, consider accessing the GraphQL `context` or memoizing any expensive calls (HTTP, database, ...) as the functions is run for each rate limited field.\n\n#### `limiterClass`\n\n\u003e An implementation of a limiter.\n\nStorage implementations are provided by [`rate-limiter-flexible`](https://github.com/animir/node-rate-limiter-flexible).\n\nSupports [_Redis_](https://github.com/animir/node-rate-limiter-flexible/wiki/Redis), process [_Memory_](https://github.com/animir/node-rate-limiter-flexible/wiki/Memory), [_Cluster_](https://github.com/animir/node-rate-limiter-flexible/wiki/Cluster) or [_PM2_](https://github.com/animir/node-rate-limiter-flexible/wiki/PM2-cluster), [_Memcached_](https://github.com/animir/node-rate-limiter-flexible/wiki/Memcache), [_MongoDB_](https://github.com/animir/node-rate-limiter-flexible/wiki/Mongo), [_MySQL_](https://github.com/animir/node-rate-limiter-flexible/wiki/MySQL), [_PostgreSQL_](https://github.com/animir/node-rate-limiter-flexible/wiki/PostgreSQL) to control requests rate in single process or distributed environment.\n\nMemory store is the default but _not_ recommended for production as it does not share state with other servers or processes. See [Redis example](examples/redis) for use in a distributed environment.\n\n#### `limiterOptions`\n\n\u003e Configuration to apply to created limiters.\n\n**WARNING**: If providing the `keyPrefix` option, consider using directive's name as part of the prefix to ensure isolation between different directives.\n\n#### `pointsCalculator`\n\n\u003e Calculate the number of points to consume.\n\nDefault with [`defaultPointsCalculator`](#defaultpointscalculatordirectiveargs-obj-args-context-info) is to cost one point.\n\n- A positve number reduces the remaining points for consumption for one duration.\n- A zero skips consuming points (like an allowlist).\n- A negative number increases the available points for consumption for one duration.\n\n#### `onLimit`\n\n\u003e Behaviour when limit is exceeded.\n\nThrow an error or return an object describing a reached limit and when it will reset. Default is to throw an error using [`defaultOnLimit`](#defaultonlimitresponse-directiveargs-obj-args-context-info). See [error example](examples/onlimit-error) and [object example](examples/onlimit-object).\n\n#### `setState`\n\n\u003e If rate limiter information for request should be stored in context, how to record it.\n\nWhen provided, puts the rate limit information for the current operation into `context`.\n\nCan be used to include formatted rate limit information in a response's `extensions`, see [example](examples/response-extension).\n\n### `defaultKeyGenerator(directiveArgs, source, args, context, info)`\n\n\u003e Get a value to uniquely identify a field in a schema.\n\nA field is identified by the key `${info.parentType}.${info.fieldName}`. This does _not_ provide user or client independent rate limiting. User A could consume all the capacity and starve out User B.\n\nThis function can be used in conjunction with `context` information to ensure user/client isolation. See [context example](examples/context).\n\n#### `directiveArgs`\n\nThe arguments defined in the schema for the directive.\n\n#### `source`\n\nThe previous result returned from the resolver on the parent field.\n\n#### `args`\n\nThe arguments provided to the field in the GraphQL operation.\n\n#### `context`\n\nContains per-request state shared by all resolvers in a particular operation.\n\n#### `info`\n\nHolds field-specific information relevant to the current operation as well as the schema details.\n\n### `defaultPointsCalculator(directiveArgs, source, args, context, info)`\n\n\u003e Calculate the number of points to consume.\n\nCost one point.\n\n#### `directiveArgs`\n\nThe arguments defined in the schema for the directive.\n\n#### `source`\n\nThe previous result returned from the resolver on the parent field.\n\n#### `args`\n\nThe arguments provided to the field in the GraphQL operation.\n\n#### `context`\n\nContains per-request state shared by all resolvers in a particular operation.\n\n#### `info`\n\nHolds field-specific information relevant to the current operation as well as the schema details.\n\n### `defaultOnLimit(response, directiveArgs, source, args, context, info)`\n\n\u003e Raise a rate limit error when there are too many requests.\n\nThrows a `GraphQLError` with message `Too many requests, please try again in N seconds.`\n\n#### `response`\n\nThe current rate limit information for this field.\n\n#### `directiveArgs`\n\nThe arguments defined in the schema for the directive.\n\n#### `source`\n\nThe previous result returned from the resolver on the parent field.\n\n#### `args`\n\nThe arguments provided to the field in the GraphQL operation.\n\n#### `context`\n\nContains per-request state shared by all resolvers in a particular operation.\n\n#### `info`\n\nHolds field-specific information relevant to the current operation as well as the schema details.\n\n### `defaultSetState(name)`\n\n\u003e Write directive state into context.\n\nHow to store the latest rate limit response in `context`, using schema coordinates.\n\n#### `name`\n\n\u003e Name of the directive.\n\n## Contributions\n\nContributions, issues and feature requests are very welcome.\n\nIf you are using this package and fixed a bug for yourself, please consider submitting a PR!\n\n## License\n\nMIT © [Rob Van Gennip](https://github.com/ravangen/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fravangen%2Fgraphql-rate-limit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fravangen%2Fgraphql-rate-limit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fravangen%2Fgraphql-rate-limit/lists"}