---
title: "Check what a forge supports"
description: "Ask a provider whether it supports an operation before you call it."
canonical_url: "https://forgeslink-3mwmle35v-poetry.vercel.app/guides/capabilities"
---
# Check what a forge supports

> Ask a provider whether it supports an operation before you call it.

Forges don't all offer the same features, so before your code relies on an operation, it makes sense to ask the provider whether the forge has it. `provider.capabilities` holds the answer for every operation. The provider computes it up front without a network request, which means checking is free. If you want to know what each value means, [Capabilities](https://forgeslink-3mwmle35v-poetry.vercel.app/concepts/capabilities) explains them.

## Call `can()` before an operation

The easiest way to check is `can()`, which takes a verb. A verb is the path of a method on the provider, such as `threads.addLabels` or `webhooks.create`. When support differs between kinds of threads, pass the kind as a second argument:

```ts
if (gh.can('threads.addLabels', thread.ref.kind)) {
  await gh.threads.addLabels(thread.ref, ['triage'])
}
```

`can()` answers `true` for both levels of support that you can use, `true` and `'emulated'`. If you want to treat an emulated operation differently, call `support()` with the same verb. It returns the level itself:

```ts
if (provider.support('notifications.markDone') === 'emulated') {
  console.info('This forge has no done state, so the notification is marked as read instead')
}
```

If you leave out the kind for a verb whose support differs by kind, you get the strongest level that any kind has. The `capabilities` object holds the same data under each verb's path, so `provider.capabilities.threads.updateComment.issue` is what `provider.support('threads.updateComment', 'issue')` reads. A page shares its listing's entry.

`support()` also says *why* an operation is missing, which `can()` does not. `false` means it is not available: the provider has not implemented it, or this credential or mode cannot reach it. `'not_applicable'` means the forge has no such operation, so there is nothing to implement and no future version of `forges` will add it. If you compare the result to `false` to mean "unsupported", note that `'not_applicable'` is a second way to be unsupported; `can()` and `isUnsupported()` cover both.

## Provide a fallback

Every method exists on every provider, even if the forge can't do what it describes. Calling such a method doesn't fail at compile time. It rejects with `UnsupportedOperationError` at run time instead. That's why it's worth checking first, so you can decide what to do when an operation is missing:

```ts
import { upsertComment } from 'forges/helpers'

if (provider.can('threads.updateComment', thread.ref.kind)) {
  await upsertComment(provider, thread.ref, {
    key: 'ci-report',
    body,
  })
}
else {
  await provider.threads.createComment(thread.ref, body)
}
```

## Check what works without credentials

An anonymous provider reports only what the forge serves to anyone. To find out whether a read needs the user to sign in, ask an anonymous provider:

```ts
import { gitlab } from 'forges/gitlab'

const publicGitLab = gitlab({})

publicGitLab.can('threads.get', 'issue') // true
publicGitLab.can('repos.labels') // false: GitLab shows labels to signed-in users only
```

## Check a stored capabilities object

Sometimes the provider isn't at hand. You might have saved its capabilities, or received them from another process. In that case, `can(capabilities, verb, kind?)` and `support(capabilities, verb, kind?)` give the same answers as `provider.can()` and `provider.support()`, from a plain capabilities object:

```ts
import { can, support } from 'forges'

const canMerge = can(saved, 'threads.merge')
const mergeLevel = support(saved, 'threads.merge')
```

## Handle version-dependent capabilities

On some forges, what you can do depends on the version of the instance. GitHub Enterprise Server, for example, supports marking notifications as done from version 3.13 onwards. Because the provider computes its capabilities without a network request, it can't know the version by itself. If you know it, pass `instanceVersion` when you create the provider. Otherwise, call `refreshCapabilities()`. It reads the version once for each provider and updates `capabilities` accordingly:

```ts
const capabilities = await forge.refreshCapabilities()
```

## Find the scopes a verb needs

Capabilities describe what the forge supports, not what your credential is allowed to do. If `can()` returns `true` and a call still fails with `InsufficientScopeError`, the credential lacks a permission. [`scopesFor()`](https://forgeslink-3mwmle35v-poetry.vercel.app/guides/authentication#show-the-scopes-an-operation-needs) tells you which one.


## Sitemap

See the full [sitemap](https://forgeslink-3mwmle35v-poetry.vercel.app/sitemap.md) for all pages.
