Pick an integration path
Before writing any code, decide which property matters most for your project: developer ergonomics, cost predictability, vendor neutrality, or trust minimisation. Each path below optimises for a different one of those.
| Path | Optimises for | Reference provider |
|---|---|---|
| Pinata SDK | Developer ergonomics, fastest time to first upload | Pinata |
| Storacha JS client / CLI | UCAN delegation, Filecoin redundancy, open protocol | Storacha |
| S3 compatible API | Reusing AWS SDK code, hybrid object plus IPFS storage | Filebase |
| IPFS Pinning Service API | Vendor neutrality, swap providers without code changes | Filebase, Pinata, Crust, others |
Path 1 — managed SDK
Upload to IPFS from Node.js with Pinata
The Pinata SDK is the lowest friction option for a Next.js, React, or Node.js project. The example below mirrors the official quickstart. The JWT is treated as a secret — keep it in a server side environment variable, not in client side code.
// npm install pinata
import { PinataSDK } from "pinata";
const pinata = new PinataSDK({
pinataJwt: process.env.PINATA_JWT!,
pinataGateway: "example-gateway.mypinata.cloud",
});
async function uploadHello() {
const file = new File(["hello world!"], "hello.txt", {
type: "text/plain",
});
const upload = await pinata.upload.public.file(file);
console.log(upload);
// { cid: "bafkrei...", name: "hello.txt", size: 12, ... }
}
async function retrieve(cid: string) {
const url = await pinata.gateways.convert(cid);
console.log(url);
// https://example-gateway.mypinata.cloud/ipfs/<cid>
}For client side uploads, generate a presigned URL on the server using pinata.upload.public.createSignedURL and pass that to the browser. The browser POSTs the file to the signed URL — the long lived JWT never reaches the client.
Path 2 — open protocol + Filecoin redundancy
Upload via the Storacha JavaScript client
Storacha (formerly web3.storage) authenticates with UCAN delegations rather than long lived API keys. The CLI is the fastest way to try it; the JS client is the recommended path for production integration.
// Install the CLI globally, then log in and create a space.
// npm install -g @storacha/cli
// storacha login you@example.com
// storacha space create my-app
// Upload via the JS client:
// npm install @storacha/client
import { create } from "@storacha/client";
const client = await create();
// Authorise with an email or import a stored agent.
const space = await client.createSpace("my-app", {
account: await client.login("you@example.com"),
});
await client.setCurrentSpace(space.did());
const files = [new File(["hello"], "hello.txt")];
const cid = await client.uploadDirectory(files);
console.log(`https://storacha.link/ipfs/${cid}/hello.txt`);Storacha uploads are content addressed by CAR (Content Archive) files and replicated to Filecoin storage providers for durability. Retrieval goes through the storacha.link gateway by default but works from any IPFS gateway.
Path 3 — reuse the AWS SDK
Upload to IPFS through Filebase's S3 API
Filebase ships an S3 compatible endpoint at https://s3.filebase.com. Any AWS SDK or S3 CLI can talk to it; objects placed in an IPFS bucket are automatically pinned and addressable by CID through the Filebase gateway.
// npm install @aws-sdk/client-s3
import { S3Client, PutObjectCommand, HeadObjectCommand } from "@aws-sdk/client-s3";
const s3 = new S3Client({
endpoint: "https://s3.filebase.com",
region: "us-east-1",
credentials: {
accessKeyId: process.env.FILEBASE_KEY!,
secretAccessKey: process.env.FILEBASE_SECRET!,
},
});
await s3.send(
new PutObjectCommand({
Bucket: "my-ipfs-bucket",
Key: "hello.txt",
Body: Buffer.from("hello world!"),
ContentType: "text/plain",
}),
);
// The IPFS CID is returned in the x-amz-meta-cid metadata header.
const head = await s3.send(
new HeadObjectCommand({ Bucket: "my-ipfs-bucket", Key: "hello.txt" }),
);
const cid = head.Metadata?.cid;
console.log(`https://ipfs.filebase.io/ipfs/${cid}`);Path 4 — vendor neutral
Talk to any provider with the IPFS Pinning Service API
The IPFS Pinning Service API (PSA) is a Protocol Labs maintained REST spec. Filebase, Pinata, Crust, ipfs-cluster, and IPFS Desktop all speak it. Code written against the PSA can swap providers by changing the endpoint and token.
// Pin an existing CID through any IPFS Pinning Service API provider.
const endpoint = process.env.PIN_ENDPOINT!; // e.g. https://api.filebase.io/v1/ipfs/pins
const token = process.env.PIN_TOKEN!;
async function pin(cid: string, name: string) {
const res = await fetch(`${endpoint}`, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ cid, name }),
});
if (!res.ok) throw new Error(`Pin failed: ${res.status} ${await res.text()}`);
return (await res.json()) as { requestid: string; status: string };
}
console.log(
await pin("bafkreidvbhs33ighmljlvr7zbv2ywwzcmp5adtf4kqvlly67cy56bdtmve", "hello.txt"),
);Reference compliance reports for each provider are published at the ipfs-shipyard pinning service compliance dashboard.
After the upload
Retrieval, IPNS, and gateway patterns
Once a file is pinned, retrieval is just an HTTP GET against an IPFS gateway. The CID is the same on every gateway; pick the one with the best latency, the SLA you need, and the takedown policy your jurisdiction can live with.
- Path style:
https://gateway.example.com/ipfs/<cid>/path— works everywhere; subject to origin sharing. - Subdomain style:
https://<cid>.ipfs.dweb.link/path— each CID gets its own origin, which helps with browser security model edge cases. - IPNS: for content that needs a stable name but changing CIDs (a static site, an app manifest), publish an IPNS name. Filebase, Storacha, and Lighthouse all support IPNS; consult the per provider page for the exact API.
- Dedicated gateway: production traffic should route through your provider's dedicated gateway with a custom domain. This gives you analytics, access controls, CDN caching, and a predictable SLA. Pinata, Filebase, Fleek, QuickNode, and 4EVERLAND all ship dedicated gateways.
Operations
Things to verify before going live
- The API key or token used by your server is scoped to write only the buckets or spaces you intend. Most providers support narrower scopes than the default admin key.
- Storage and bandwidth allowances are set high enough for peak traffic plus a margin. Bandwidth overages are the most common source of surprise bills.
- Retrieval works through both your dedicated gateway and at least one public fallback (ipfs.io or dweb.link). Public gateways will eventually return your CID once it propagates the DHT.
- You have a content takedown policy. Public IPFS content is replicated outside your control; CIDs cannot be revoked. Sensitive content goes in a private IPFS bucket (Pinata) or stays off IPFS entirely.
- For long term durability, layer a Filecoin backed provider on top of, or instead of, a pure hot pinning service. Storacha and Lighthouse both back their pins with Filecoin storage deals.
Pick a provider
See the full side by side comparison at /ipfs or jump to a specific provider: