One of the most common interactions with IPFS is uploading files like images and videos from a client-side application, so I found it surprising that there were not a lot of straightforward tutorials showing how this is done.
In this tutorial you will learn just that in as few lines of code (and as simply) as possible using ipfs-http-client
. The ideas here are implemented in React but should be fairly easily transferrable to doing the same thing in any other JavaScript framework, like Vue, Angular, or Svelte.
About IPFS
IPFS is a decentralized, peer to peer file sharing protocol.
There are various types of IPFS gateways available. Some are free, some are not. Some offer read-only access, and others offer both read and write access.
You can also run your own IPFS gateway.
Because we will be uploading / saving files, we need to be sure to choose a gateway that allows us write access. The gateway we will be using today is Infura. Other popular services are Pinata or Fleek.
For this example to work, you need to sign up with Infura and get a project ID and API secret.
For an example of how to pin a file to IPFS with Pinata, check out this repo.
Getting started
If you already have a React application created, you can skip this step.
First, create a new React app and change into the new directory:
npx create-react-app ipfs-example
cd ipfs-example
Next, install the ipfs-http-client
library and buffer
using either NPM or Yarn:
npm install ipfs-http-client buffer
Base code
The basic functionality can be summed up in these lines of code, but I'll also be building out an entire UI to show how it all fits together.
The basic code for getting this to work is here:
/* import the ipfs-http-client and buffer libraries */
import { create } from 'ipfs-http-client'
import { Buffer } from 'buffer'
/* configure Infura auth settings */
const projectId = "<your-infura-project-id>"
const projectSecret = "<your-infura-project-secret>"
const auth = 'Basic ' + Buffer.from(projectId + ':' + projectSecret).toString('base64')
/* Create an instance of the client */
const client = create({
host: 'ipfs.infura.io',
port: 5001,
protocol: 'https',
headers: {
authorization: auth,
}
})
/* upload the file */
const added = await client.add(file)
/* or a string */
const added = await client.add('hello world')
Full code
Let's now look at how the above code would be used to actually implement file upload functionality in our app for uploading and viewing images.
In your project, open src/App.js and update it with the following code:
/* src/App.js */
import './App.css'
import { useState } from 'react'
import { create } from 'ipfs-http-client'
import { Buffer } from 'buffer'
/* configure Infura auth settings */
const projectId = "<your-infura-project-id>"
const projectSecret = "<your-infura-project-secret>"
const auth = 'Basic ' + Buffer.from(projectId + ':' + projectSecret).toString('base64');
/* create the client */
const client = create({
host: 'ipfs.infura.io',
port: 5001,
protocol: 'https',
headers: {
authorization: auth,
},
})
function App() {
const [fileUrl, updateFileUrl] = useState(``)
async function onChange(e) {
const file = e.target.files[0]
try {
const added = await client.add(file)
const url = `https://infura-ipfs.io/ipfs/${added.path}`
updateFileUrl(url)
console.log("IPFS URI: ", url)
} catch (error) {
console.log('Error uploading file: ', error)
}
}
return (
<div className="App">
<h1>IPFS Example</h1>
<input
type="file"
onChange={onChange}
/>
{
fileUrl && (
<div>
<img src={fileUrl} width="600px" />
<a href={fileUrl} target="_blank">{fileUrl}</a>
</div>
)
}
</div>
);
}
export default App
Next, run the app:
npm start
When the app loads, you should see a file upload button.
Once a file has been successfully uploaded, you should see it rendered in the UI.
Top comments (31)
Hi, there was an update on IPFS and your code does not work anymore...
Failed to load resource: the server responded with a status of 401 (Unauthorized)
Can you update your code please
Thanks in advance
Hi there,
I have check the code again and its working fine may be you have forgot to use your own project id and project key in App.jsx component check the App.jsx component try it again and let me know.
the infura public gateway didnt for free anymore, we need to use another public gateway or pay for the IPFS Infura service
yes but you can use the dedicated gateway for free you don't need to pay for public gateways.
thanks, could you recommend me any services?
yah any recommendations please?
web3.storage
yes bro did you got any solution for it??
I'm stuck with this issue now....
Help me this please infura stopped pubilc gateways i have running local ipfs node how can i upload files to that???
please help me with this I'm stucked......
This is fire! I'm glad I've got friends like you. Definitely layering this into my graphql api. What I also find interesting is that you can run your own node locally but it still connects to the ipfs network. 🤯
💙
Hey! I was asking if you could guide me on achieving this using a local ipfs gateway.
Hi there, great article, I am doing the same thing, but this error pops up, do you have any idea why?
I am using react and not electron, that's weird for me.
node_modules/electron-fetch/lib/index.es.js:1257:21: error: Could not resolve "electron" (mark it as external to exclude it from the bundle, or surround it with try/catch to handle the failure at run-time)
Im getting the same error using vite. Any luck solving this?
My error is Uncaught SyntaxError: The requested module '/node_modules/merge-options/index.js?v=7ace0d54' does not provide an export named 'default'
Can anyone help me ,, I use vite and react , seems
import { create } from 'ipfs-http-client';
doesn't work fine in this case ??web3.storage/
github.com/Lschulzes/photo_blockch...
Hey, I ended up switching to Web3Storage, I also used vite.
Just delete 'electron-fetch' from 'node_modules'. I think it should work.
Hi, Thanks for the content. This actually helped.But whenever I select a file, it processess for a while and get the error
GET https://ipfs.infura.io/ipfs/QmcBKzWSSXbR9JSGHbiBRoGFLcKashii6rS4QeS66uHejK Bad Request 400
what could be the problem??
Could someone tell me how to do this for 10000 NFTs? as I need to upload the arts as well as the metadata on ipfs. Also, when the arts are going to be uploaded? The moment the buyers mint the NFTs or before that all the NFTs need to be upload? Thanks
Hi IPFS developers. When you use IPFS to publish file, You need to purchase a VPS to run your IPFS node also pin service like pinata to pin your file. Now we have cheapest solution called Foggie. With Foggie , you can get a 2C4G VPS, 80G storage,4T bandwith with pin service for only $19.9. Also , when you use it, you can get token and NFT rewards, letting you earn money. If you want to know more, Here is the link: https://foggie.fogworks.io/?pcode=uZVcLL&cc=1008#/fogworks
I use vite and react to develop,, after implementing this method,, I got some errors ->
Uncaught SyntaxError: The requested module '/node_modules/merge-options/index.js?v=7ace0d54' does not provide an export named 'default'
Really dont know how to solve this? are there some problems like curly braces in
import { create } from 'ipfs-http-client';
???@dabit3 Thx~~
Hi @dabit3 I am facing issue when running the code. I followed your YouTube tutorial and tried this snippet as well, but seeing below error for both Infura and pinata.
Please help.
Error: Unhandled Runtime Error
TypeError: debug__default.default is not a function.
No worries. I figured it out. It was due to deprecated debug package. I've updated the package in package.json and run npm install --save, it started working.
Getting error Unhandled Runtime Error
TypeError: debug__default.default is not a function.
Seeing the same issue. Were you able to resolve it?
My error was due to ipfs and it got fixed using command
npm i ethers@5.5.1 ipfs-http-client@50.1.2 @babel /core --save
This worked like a Charm! Thanks a Lot 😄