> For the complete documentation index, see [llms.txt](https://8bit-1.gitbook.io/solibrary/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://8bit-1.gitbook.io/solibrary/registering-programs.md).

# Registering Programs

Umi offers a `ProgramRepositoryInterface` that acts as one big registry of programs for you client.

This also allows us to:

* Register programs from other libraries.
* Register our own programs and override existing ones.
* Fetch programs by name or public key in our current cluster or a specific one.
* Resolve program errors by name or code.

### Defining Programs <a href="#defining-programs" id="defining-programs"></a>

Umi provides a `Program` type that represents a Solana program. It contains the program's name, public key, and some functions that can be used to resolve its errors and which cluster it has been deployed to.

```
export type Program = {
  name: string;
  publicKey: PublicKey;
  getErrorFromCode: (code: number, cause?: Error) => ProgramError | null;
  getErrorFromName: (name: string, cause?: Error) => ProgramError | null;
  isOnCluster: (cluster: Cluster) => boolean;
};
```

You can [learn more about the attributes of the `Program` type via its API reference](https://umi.typedoc.metaplex.com/types/umi.Program.html) but note that the `name` attribute should be unique and, by convention, should be use the camelCase format. To avoid conflict with other organizations, it is recommended to prefix the program name with a namespace that is unique to your organization. For instance, Metaplex programs are prefixed with `mpl` like so: `mplTokenMetadata` or `mplCandyMachine`.

### Adding Programs <a href="#adding-programs" id="adding-programs"></a>

To register a new program to the program repository, you may use the `add` method of the `ProgramRepositoryInterface` like so.

```
umi.programs.add(myProgram);
```

If this program already exists in the repository — i.e. it has the same name or public key for at least one conflicting cluster — it will be overridden by the newly added program. To change this behavior, you may set the second argument `override` to `false`. In the example below, this program will only the retrieved if no other registered program matches the user's query.

```
umi.programs.add(myProgram, false);
```

### Fetching Programs <a href="#fetching-programs" id="fetching-programs"></a>

Once a program is registered, you may fetch it by its name or public key via the `get` method. This will return the program if it exists in the repository. Otherwise, it will throw an error.

```
// Fetch a program by its name.
const myProgram = umi.programs.get('myProgram');

// Fetch a program by its public key.
const myProgram = umi.programs.get(publicKey('...'));
```

By default, the `get` method will only return programs that are deployed to the current cluster — such that the `isOnCluster` method returns `true` for the current cluster. It is only possible to specify a different cluster via the second argument that accepts a [`ClusterFilter`](https://umi.typedoc.metaplex.com/types/umi.ClusterFilter.html).

A `ClusterFilter` can either be an explicit [`Cluster`](https://umi.typedoc.metaplex.com/types/umi.Cluster.html), `"current"` to select the current cluster, or `"all"` to select programs that are deployed to any cluster.

```
// Fetch a program on the current cluster.
umi.programs.get('myProgram');
umi.programs.get('myProgram', 'current');

// Fetch a program on a specific cluster.
umi.programs.get('myProgram', 'mainnet-beta');
umi.programs.get('myProgram', 'devnet');

// Fetch a program on any cluster.
umi.programs.get('myProgram', 'all');
```

It is also worth noting that the `get` method is generic and can return a superset of the `Program` type. For instance, say you have a `CandyGuardProgram` type that extends the `Program` type in order to store the `availableGuards` on that program. Then, if you know that the program you are fetching should be of that type, you may tell the `get` method by setting its type parameter to `CandyGuardProgram`.

```
umi.programs.get<CandyGuardProgram>('mplCandyGuard');
```

Additionally, the `ProgramRepositoryInterface` provides a `has` method that can be used to check if a program exists in the repository and a `all` method to retrieve all programs in the repository. Both of these methods accept the same `ClusterFilter` argument as the `get` method.

```
// Check if a program exists in the repository.
umi.programs.has('myProgram');
umi.programs.has(publicKey('...'));
umi.programs.has('myProgram', 'mainnet-beta');
umi.programs.has('myProgram', 'all');

// Retrieve all programs in the repository.
umi.programs.all();
umi.programs.all('mainnet-beta');
umi.programs.all('all');
```

Finally, since fetching the public key of a program is a common operation, the `ProgramRepositoryInterface` provides a `getPublicKey` method that can be used to fetch a program's public key directly. A `fallback` public key can be provided to avoid throwing an error if the program does not exist in the repository and return the given public key instead.

```
// Get the public key of a program.
umi.programs.getPublicKey('myProgram');

// Get the public key of a program with a fallback.
const fallback = publicKey('...');
umi.programs.getPublicKey('myProgram', fallback);

// Get the public key of a program on a specific cluster.
umi.programs.getPublicKey('myProgram', fallback, 'mainnet-beta');
```

### Resolving program errors <a href="#resolving-program-errors" id="resolving-program-errors"></a>

The `ProgramRepositoryInterface` provides a `resolveError` method that can be used to resolve a custom program error from a transaction error. This method accepts any `Error` with a `logs` attribute and the `Transaction` instance that originated this error. It then returns an instance of `ProgramError` if a custom program error was identified from the error logs. Otherwise, it returns `null`.

```
umi.programs.resolveError(error, transaction);
```
