Replace Vercel Blob with Google Cloud Storage

Replace Vercel Blob with Google Cloud Storage

While vercel blob has very tight integration with NextJS, it is still in private beta. It is fairly expensive too. Storing files in your cloud storage gives you more flexibility and cost savings.

This tutorial explains how you can replace the Vercel Blob API with Google Cloud Storage API using the example of Vercel Multi-tenant Platform Starter Kit template. This template is often used by those who wish to create multi tenant applications using nextjs.

Table of contents

  1. The template

  2. Setting up Google Cloud Credentials

    1. Define environemnt variable
  3. GCP Storage Library

  4. Replacing the Vercel Blob references.

  5. Caution

The template

There are many templates provided by vercel that uses the blob storage. We take one of these as an example. Particularly we have picked their platforms starter kit template here.

Setting up Google Cloud Credentials

We will not go into the process of creating a Google cloud project and downloading the google_credentials.json file. That tutorial can be found here.

Once you follow this process you will get a json file that contains everything to authenticate you with Google Cloud.

Copy the contents of this file and convert it into Base64 encoded string by pasting it here. Note that this file is sensitive so you should ideally covert it into base64 using some local tool that wont steal these credentials. But for simplicity I have given you this link.

Define environemnt variable

Define an environment variable GOOGLE_CREDENTIALS and set its value to this base64 encoded string. If you are using Vercel then you can set this environment variable in your vercel dashboard.

GCP Storage Library

Create a file "lib/gcs.ts" in your code and paste the following code.


// Run npm install @google-cloud/storage --save if you have not already.
import { Storage } from "@google-cloud/storage";

const createWriteStream = (filename: string, contentType?: string) => {
const credentials = JSON.parse(
Buffer.from(process.env.GOOGLE_APPLICATION_CREDENTIALS!, "base64").toString().replace(/
/g,"")
)
const storage = new Storage({
projectId: credentials.project_id,
credentials: credentials
});
const bucket = storage.bucket(process.env.GCS_BUCKET as string);

const ref = bucket.file(process.env.GCS_PUBLIC_PATH + "/" + filename);

const stream = ref.createWriteStream({
gzip: true,
contentType: contentType,
});
stream.on("finish", () => {
ref.makePublic();
});

return stream;
};

export const putFile = async (filename: string, file: File): Promise<string> => {
let writeStream = createWriteStream(filename, file.type);
const bytes = await file.arrayBuffer()
const buffer = Buffer.from(bytes)
const copyPromise = new Promise<string>((resolve, reject) => {
writeStream.on("error", (reason)=>{
reject(reason);
});
// writeStream.on('error', reject);
writeStream.on('finish', ()=> {
resolve("https://storage.googleapis.com/"+process.env.GCS_BUCKET+"/"+process.env.GCS_PUBLIC_PATH+"/"+filename);
});
writeStream.write(buffer);
writeStream.end();
});
return copyPromise;
}

You now have the basic API to upload a file to Google cloud and return a URL.

Replacing the Vercel Blob references.

Now how your app uploads the file from browser to server is upto you. However for this particular example we have code that looks something like this.


const file = formData.get(key) as File;
const filename = nanoid()+"."+file.type.split("/")[1];

const { url } = await put(filename, file, {
access: "public",
});


You can simply replace thie code with


// at the top of the file
import { putFile } from "@/lib/gcs";

// At appropriate location in the code
const file = formData.get(key) as File;
const filename = nanoid()+"."+file.type.split("/")[1];
const imageUrl = await putFile(filename,file);


Caution

We have not implemented things like error handling, limits on upload size, file type checks etc. But this code should give you an idea of how simple this code is. Also, Vercel blob puts your files on a CDN. Google Storage too supports such feature and you should explore that more.

Please write to us on writers@frontendeng.dev if you have any concerns or if you want any consultation.