Open-source project
unjs/ungh avatar
unjs/ungh

ungh: a cached, anonymous layer in front of the GitHub API

🐙 Unlimited access to github API

691 stars29 forksTypeScriptMIT

At a glance

What is it?
ungh is a public service that wraps the GitHub REST API in a simplified, cached and anonymous layer, so a page that wants repository metadata, contributors, releases, branches or star counts does not need a token and does not have to live with the rate limit or the payload size of the upstream API. It is built on Nitro, cached in Redis, and deployed on Vercel.
Who is it for?
ungh is worth using in a small project or a static site that needs repository metadata at build time, because the endpoints are small, the shapes are stable and there is no token to manage, and the cache means the service is cheap to depend on. It is the wrong tool if you need write access, anything the API does not expose through the listed endpoints, or data that has to be current to the second, because the whole design is a cache in front of a rate limited API.
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 last received commits 4 days ago.
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 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why a proxy for an API that already exists

ungh is described as unlimited access to the GitHub API, and the README gives the reasons for building it in a paragraph that is worth reading closely.

Accessing open source GitHub repository metadata should be fast, easy and straightforward. The GitHub API is rate limited and requires an authentication token to increase the limits. Even with a token, you need to share or generate one for each deployment and each local development environment, and you still have to deal with the increased rate limits and with deployment caching. The GitHub REST API is also complex, with unnecessarily bigger payloads because of backward compatibility.

So the pitch is a simplified, cached and anonymous layer. Each of those three words maps to a specific complaint. Simplified addresses the payload size and the shape of the response. Cached addresses the rate limit. Anonymous addresses the token problem, which is the one that most often stops a small project from using the API at all.

The service is unjs, the same organisation behind h3 and the other tools in the examples, and the site is ungh.cc. The project was developed by pi0 and contributors, it is MIT licensed, the last push was on 2026-10-18 and the repository is not archived, with no GitHub releases published.

The hosting is Vercel, and the README says hosting is sponsored by Vercel, which is the kind of arrangement that decides where a free public service actually lives.

The repository endpoint returns a trimmed object, not the GitHub shape

The first endpoint is the one everything else is built on, and its response shows the trimming in action.

json
{
  "repo": {
    "id": 313641207,
    "name": "h3",
    "repo": "unjs/h3",
    "createdAt": "2020-11-17T14:15:44Z",
    "updatedAt": "2022-11-05T21:38:43Z",
    "pushedAt": "2022-11-06T06:48:23Z",
    "stars": 1168,
    "watchers": 1168,
    "forks": 59,
    "defaultBranch": "main"
  }
}

The date fields are renamed to camelCase with an At suffix, so updatedAt and pushedAt rather than updated_at and pushed_at. The owner and name are collapsed into a single repo field of the form owner/name. The full name appears separately as name. Everything else that GitHub returns for a repository, and there is a great deal of it, is not in the response.

That is the point of the service, and it is also its main constraint. If you are migrating an existing GitHub API call, you are not getting the same object with fewer fields, you are getting a different object, and the fields that are present are named differently.

There is a second, smaller trimming in the star counts. The response reports stars and watchers with the same number, which is what GitHub itself does for a repository, but it means the two fields are not independent in the response and there is no separate subscribers count.

The other repository endpoints follow the same pattern of a single top-level key wrapping the useful data, and the contributors endpoint is the clearest example of the shape, returning an id, a username and a contribution count per entry.

Files, readme, releases and branches, and one endpoint that redirects

The files endpoint is the one to understand before you build on the service, because it does not behave like the others.

The README carries an important note at the top: the /repos/<id>/files/<path> endpoint redirects to the original raw.githubusercontent.com endpoint because of service abuse. The issue is linked, and the reason is not hard to guess, since serving arbitrary file trees as a proxy for GitHub's content host is the kind of traffic that attracts abuse.

The response shape is otherwise a tree with a meta object holding the commit sha, and a files array where each entry has a path, a mode, a sha and a size:

json
{
  "meta": {
    "sha": "501f0c6e623ea827d47691046f3c7319f5ac4651"
  },
  "files": [
    {
      "path": "README.md",
      "mode": "100644",
      "sha": "4c2b9ce4bccd6e046cd71be1a8c5e53a62778858",
      "size": 5782
    }
  ]
}

The readme endpoint is explicitly not cached, which the README states in as many words, and it returns both the html and the markdown rendering of the readme rather than the raw file, so you do not have to render it yourself.

The releases endpoints come in two forms, a list and a latest, and the list entries carry the tag, the author, the name, the draft and prerelease flags, the creation and publication timestamps, and both the markdown and the html body.

The branches endpoint returns a name, the commit with its sha and the api.github.com url, and a protected flag, and the example in the README shows a protected main branch alongside two Renovate branches that are not protected, which is what a repository with dependency automation enabled looks like.

Stars, organisations and user lookup, including by email

The remaining endpoints cover the queries a project page or a sponsor page tends to need.

The stars endpoint is the one with the most interesting design. It takes one or more repositories or organisations in a single path, and the README states that multiple items can be separated by either a comma, a plus sign or a space. Each item can be an owner/name pair to specify one repository, or owner/* to specify all the repositories of an organisation. The response carries a total and a map:

json
{
  "totalStars": 51524,
  "stars": {
    "nuxt/nuxt.js": 41560,
    "nuxt/framework": 9964
  }
}

That is a single request for a set of counts, which is the kind of aggregation the upstream API cannot do in one call.

The organisation endpoints give the org itself, with an id, a name and a description, and the list of its repositories, each entry carrying the same trimmed repository shape as the first endpoint.

The user endpoints are the last pair, and one of them is unusual. /users/{username} finds a user by username, returning an id, a name, a twitter handle and the username. /users/find/{query} finds a user by email or other query, and the example uses an email address. Since GitHub's own API exposes user email addresses only under certain conditions, an endpoint that can look a user up by email is doing something the upstream API deliberately restricts.

For an application that needs to attribute a commit to a person, or that wants to show an avatar, that is a genuinely useful capability and also one worth thinking about from a privacy angle.

Nitro, Redis and a nightly dependency

The implementation is a Nitro server, and the repository layout shows a conventional serverless application.

The top-level entries are routes/ for the API endpoints, middleware/, utils/ and types/ for the code, nitro.config.ts for the server configuration, a public/ directory, and a test/ directory with a vitest.config.ts. The package.json scripts are the standard Nitro set, with build, dev and preview for the server, and the test script is a chain of lint, typecheck and a coverage run.

The caching is Redis, and the @upstash/redis package in the devDependencies is the client, which points at Upstash as the provider rather than a self-hosted Redis. The .env.example file at the root contains a single variable, GH_TOKEN, which is the GitHub token the service itself uses on the server side, even though the public API is anonymous. That is the whole point: one token, held by the operator, in front of many anonymous callers.

Two dependencies are worth a note because they are unusual. The nitro dependency is pinned to nitro-nightly@latest, so the server framework is tracking a nightly build. The typescript entry is a version 7 dependency with a matching native preview package, and the typecheck script runs tsgo rather than tsc. The package manager is pinned to pnpm 11.28.4, and the linting is oxlint with oxfmt for formatting, which is a newer and much faster stack than the usual eslint and prettier.

For a contributor, the development setup is four steps in the README: clone the repository, enable Corepack with corepack enable, install dependencies with pnpm install, and run the interactive tests with pnpm dev.

Editorial conclusion

ungh is worth using in a small project or a static site that needs repository metadata at build time, because the endpoints are small, the shapes are stable and there is no token to manage, and the cache means the service is cheap to depend on. It is the wrong tool if you need write access, anything the API does not expose through the listed endpoints, or data that has to be current to the second, because the whole design is a cache in front of a rate limited API. Before you rely on it, verify three things yourself: that the fields you need are present in the responses, since the payloads are trimmed and some upstream fields are dropped, that the caching delay is acceptable for your use, since a stars count or a file tree can be stale, and that you have a fallback, because the file listing endpoint redirects to raw.githubusercontent.com, which the README flags as a service abuse issue and which means that one endpoint does not behave like the others.

Frequently asked questions

What is the ungh service?

It is a public, cached and anonymous layer in front of the GitHub REST API, described as unlimited access. The README says accessing open source repository metadata should be fast and straightforward, and points to rate limits, the need for a token and the size of upstream payloads as the problems it solves.

Do I need a GitHub token to use ungh?

No. The public API is anonymous, which is one of the stated reasons for the service, since a token would otherwise have to be shared or generated for every deployment and local environment. The operator of the service holds its own token, configured as GH_TOKEN in the .env.example.

Which endpoints does ungh expose?

Repository information, contributors, the file tree, the readme, releases and the latest release, branches, organisation information and its repositories, star counts for one or more repositories or organisations, user lookup by username, and user lookup by email or other query.

What is the known problem with the ungh files endpoint?

The README notes that the /repos/<id>/files/<path> endpoint redirects to the original raw.githubusercontent.com endpoint because of service abuse, with the issue linked. That means the file tree endpoint behaves differently from the rest of the API.

How do I run ungh locally?

Clone the repository, enable Corepack with corepack enable, install the dependencies with pnpm install, and run the interactive tests with pnpm dev. The server is built with Nitro, and the package manager is pinned to pnpm 11.28.4.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. unjs/ungh on GitHub
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/unjs-ungh.svg)](https://hysenlabs.com/projects/unjs-ungh)