# IPFS Overview & Ternoa IPFS Client

### Overview

IPFS (Interplanetary File Systems) is one of the solutions we recommend to upload NFTs media and other associated metadata. Thus off-chain data are stored in a fully decentralized way and only the link to this metadata is stored on-chain as part of the NFT. This link is frequently a fingerprint called a cryptographic hash ID (e.g. `Qmf5RHhnUjSCfCN9d1Ee6sUWxe3Eqvogw1cTsssrxAxtPn`). IPFS files are accessible using those hashes.

On Ternoa NFTs are composed of two files: an asset file (e.g. image, video, music) and a metadata JSON file. The asset file hash is nested into the metadata file and both are stored on IPFS with their dedicated hashes.

Ternoa provides its own IPFS public nodes on different HTTP gateways based on the network environment:

* Mainnet: [https://ipfs-mainnet.trnnfr.com](https://ipfs-mainnet.trnnfr.com/)
* Alphanet: [https://ipfs-dev.trnnfr.com](https://ipfs-dev.trnnfr.com/)

{% hint style="info" %}
Please note that a *api-key* is needed to store data on those gateways. Visit the next [section](/build-1/javascript/decentralized-storage/ipfs-key-manager.md) and the [IPFS Key Manager](https://ipfs-key-manager-git-dev-ternoa.vercel.app/) to obtain your API Key. **After being generated, the key may need a few minutes to become effective for use with the Ternoa client.**
{% endhint %}

### Ternoa IPFS Client

An IPFS client is available on ternoa-js SDK to make IPFS upload simple with only one line of code.

Here is an example of uploading an image "shining.jpg" from the movie:

```typescript
import { TernoaIPFS, File } from "ternoa-js";

const main = async () => {
  const file = new File(
    [await fs.promises.readFile("shining.jpg")],
    "shining.jpg",
    {
      type: "image/jpg",
    }
  );

  const ipfsClient = new TernoaIPFS(new URL("IPFS_NODE_URL"), "IPFS_API_KEY");

  const nftMetadata = {
    title: "Shining, a nice movie",
    description: "This is (not) my first Ternoa's NFT",
  };

  const { Hash } = await ipfsClient.storeNFT(file, nftMetadata);
  console.log("The off-chain metadata hash is ", Hash);
};
```

First, the JPG image file named "shining.jpg" is read from the file system and wrapped in a specific `File` instance. The TernoaIPFS class is then used to create an IPFS client that connects to a specified IPFS node using a given API key. The metadata for the file is then defined in an object and passed to the `storeNFT` method of the client along with the `File` instance. The resulting `Hash` of the off-chain metadata is logged to the console.

The `storeNFT` method handles two IPFS uploads under the hood: a first one with the NFT media (e.g. the image) and a second one with the JSON metadata file, including the media's hash from the first upload response. This method also validates the metadata structure to ensure TIPs compatibility.

Additional methods are provided to handle secret NFTs, collections, and the marketplace. They worked in the same manner and were respectively: `storeSecretNFT`, `storeCollection`, and `storeMarketplace`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ternoa.network/build-1/javascript/decentralized-storage/ipfs-overview-and-ternoa-ipfs-client.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
