Skip to content

Repository files navigation

parse-github-gql-global-id

Encode and decode GitHub's GraphQL global node IDs — all 354 of them, including the ones that carry more than a database ID.

decodeNodeId('I_kwDOAJy2Ks4A47jA');
// { typeName: 'Issue', scope: 'ri', fields: { repo_id: 10270250, issue_id: 14923968 }, id: 14923968, ... }

Install

pnpm add parse-github-gql-global-id

How the IDs work

A modern ("next") node ID is a type prefix, a _, and a base64url-encoded MessagePack array:

I_kwDOAJy2Ks4A47jA  ->  "I" + "_" + msgpack([0, 10270250, 14923968])

The prefix names the GraphQL type. The array's first element is a template index, and the rest are that template's values. Each type declares its templates, so the payload is self-describing once you know the prefix:

Type Prefix Template
User U [id]
Repository R [id]
Issue I [repo_id, issue_id]
Commit C [repo_id, oid]
MentionedEvent MEE [repo_id, issue_id, id]
Reaction REA 7 templates, one per reactable type

Values are usually database IDs, but they can also be strings — a commit oid, a qualified_name like refs/heads/main, a topic name, a license key.

Older IDs (MDQ6VXNlcjE=) are base64 of 0<len>:<Type><id>; those are handled too.

Usage

import {
  decodeNodeId,
  encodeNodeId,
  encodeNodeIdWithFields,
  extractDatabaseId,
  extractRepositoryId,
  parseNodeId,
} from 'parse-github-gql-global-id';

// Decode
decodeNodeId('C_kwDOACN7MtoAKDUwMmQ0NTc3NGFmMDlmMWM2ODFjNzU0YzRiN2NkZmI1ZDdmNzJmZDk');
// {
//   format: 'next',
//   prefix: 'C_',
//   typeName: 'Commit',
//   templateIndex: 0,
//   scope: 'rc',
//   fields: { repo_id: 2325298, oid: '502d45774af09f1c681c754c4b7cdfb5d7f72fd9' },
//   values: [2325298, '502d45774af09f1c681c754c4b7cdfb5d7f72fd9'],
//   id: '502d45774af09f1c681c754c4b7cdfb5d7f72fd9',
// }

// Encode by position (uses the type's first template)
encodeNodeId('User', 1);                    // "U_kgAB"
encodeNodeId('Issue', 10270250, 14923968);  // "I_kwDOAJy2Ks4A47jA"

// Encode by field name — order-independent, and picks the matching template
encodeNodeIdWithFields('Commit', { repo_id: 2325298, oid: '502d4577…' });
encodeNodeIdWithFields('App', { org_id: 9919, app_id: 15368 });  // template `oa`

// Shortcuts
extractDatabaseId('I_kwDOAJy2Ks4A47jA');    // 14923968
extractRepositoryId('I_kwDOAJy2Ks4A47jA');  // 10270250

// Either format
parseNodeId('MDQ6VXNlcjE=');  // { format: 'legacy', typeName: 'User', id: '1' }

When a type has several templates with the same field names — ProjectV2 has one for org owners and one for user owners — pass the scope:

encodeNodeIdWithFields('ProjectV2', { owner_id: 1, id: 2 }, { scope: 'upvt' });

API

Export Description
decodeNodeId(id) Decode a next-format ID into type, template, and named fields
decodeLegacyNodeId(id) Decode a legacy (Relay) ID
parseNodeId(id) Decode either format
encodeNodeId(type, ...values) Encode from positional values
encodeNodeIdWithFields(type, fields, options?) Encode from named fields
encodeLegacyNodeId(type, id) Encode a legacy ID
encodeUserNodeId / encodeBotNodeId / encodeOrganizationNodeId / encodeRepoNodeId Top-level owner shortcuts
extractDatabaseId(id) / extractId(id) / extractRepositoryId(id) Pull single values out
isNextNodeId(id) / isLegacyNodeId(id) Format detection
getTypeMetadata(typeOrPrefix) Prefix and templates for a type
GLOBAL_ID_METADATA / TYPE_NAME_BY_PREFIX The full registry

Type names and prefixes are both accepted wherever a type is expected, and GlobalIdTypeName is a union of all 354 names, so editors autocomplete them.

Migrating from 1.x

  • decodeNodeId returns values instead of ids, plus typeName, scope, and fields. prefix is unchanged.
  • encodeNodeId now knows each type's shape and throws a NodeIdError on the wrong number of values. encodeNodeId('Issue', issueId) was producing an invalid ID; it needs encodeNodeId('Issue', repoId, issueId).

Notes

  • IDs larger than Number.MAX_SAFE_INTEGER decode to a bigint; smaller ones stay number. Encoding accepts either.
  • The GraphQL API only returns next-format IDs when you send X-Github-Next-Global-ID: 1; the REST API returns them for node_id under the same header.
  • pnpm test-online checks the library against the live API — crafting IDs for known users, repositories, and organizations, and round-tripping every ID returned by a broad sweep of a few large repositories.

About

Parse and generate GitHub GraphQL global ids. Convert to and from the REST API ids.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages