Lesson Description
The "Upload Images" Lesson is part of the full, Build a Fullstack Next.js App, v4 course featured in this preview video. Here's what you'd learn in this lesson:
Brian shows how to upload images using Vercel Blob, configure environment variables, and integrate the uploads with articles in a Next.js project, letting Next Image handle optimization automatically.
Transcript from the "Upload Images" Lesson
[00:00:00]
>> Brian Holt: And again, there's a trillion different products that do this. I had started using Cloudinary for this, which is another great, like if you're specifically doing like images and videos, you want to be able to like edit those on the fly. Cloudinary is great. Azure blob storage would work for this as well. Minio, if you want to host it yourself, there's a bunch.
[00:00:19]
In our case, Vercel already had it and I was like, well, you already have a Vercel account. Why am I going to make you sign up for more accounts? So we are just going to use it. For action upload.ts here. So we're in the upload app here and up at the top, we're going to import put from @vercel/blob. Okay, and we're going to replace the mock code here.
[00:00:59]
So I put all the validation in here. This is basically, is it an image, is it too big, all that kind of stuff. Nobody cares, no one wants to write that stuff over and over again. That's what all this is doing. And here we're going to replace all of this. So I'm going to say try, const blob equals await, put file.name, file, access is public because this is like a publicly accessible image because it's going on a wiki, and add random suffix to be true, because we don't want collisions.
[00:01:40]
If someone's uploading image.jpg eventually that's going to collide with somebody else's image.jpg. Okay, if that succeeds, then we just want to return URL. I think I have blob as any, but I think it's going to yell at us for doing that URL because it doesn't like any. Yeah. We'll figure out how to fix that in just a second. Size, file.size, type, file.type.
[00:02:19]
This is all just like the response back to the client. File name is blob. Result. Where did blob.results even come from? I don't know. What's his pathname. File.name. Just do URL. It seems fine. I don't know why we needed any sort of. Yeah, that's way easier. Why are we doing this any casting? Okay, so that's the return statement. We do need a catch.
[00:03:08]
And I did put a catch in here because I did find this fail from time to time. That's just kind of like working with blob storage, that's not uncommon. So I wanted to have a more useful error message here. We'll put an x. Reel blob, upload error, and I'll put the error. And then throw new error. Upload failed. Okay. So let's go try this now. What's it mad about?
[00:03:57]
Is it mad about something specific? Oh, there's something wrong with my syntax here. That's Prettier mad. Try is not. Missed a comma there after the file. Oh, there we go. Here we go. Cool. Okay, now let's go to action/articles.ts. And now the image URL is going to be, where is the image URL. To create article. It's going to have an image URL and that's either going to be data.imageURL or undefined.
[00:05:06]
Now why do I do undefined like this? It's actually more interesting here. I'm not, you could put null there, but that's actually explicitly inserting the null type there. And like that's actually not what we're expecting, we're just expecting it to not be set. And it's the same thing here. This is even more important because if I put like empty string or null here, it would detect that's actually being set to something and then if there was an image there that they were editing and trying to just leave there, it would override it with nothing, which is not what we want.
[00:05:37]
We don't want them to have to upload the image every single time to keep the image. So here we have to unset it, which is what you want with undefined. I know some people will get like, undefined can technically be redefined in JavaScript in certain ways, so if you put void zero, you're actually guaranteeing that it will be undefined. My point to everybody is that if your undefined gets remodified to be something else in your code, there's something very wrong with your code, and this is not the core problem of what you're doing.
[00:06:10]
So, I just put undefined because that's actually more what I expect. And actually, in theory, because this can already be undefined, you really can put this, because if it does get redefined that way, then, but whatever, we'll leave it like this. So, last place, lib/data/articles, lib/data/articles, we do need to select the image URL out of here as well.
[00:06:44]
Not on the get articles, but on this one. It looks like we already have it. Oh, cool. Just weren't doing anything with it. So we have to go fix one thing. .env here, we call this API key, it's actually supposed to be called blob read-write token. That's a specific name that the Vercel SDK looks for in the environment, so if it's not called that, it won't find it.
[00:07:25]
So I had this call API key, please call it blob read-write token. Okay. So npm run dev. Open our page. Here we're going to read an article that we can edit. Edit this article. Blah upload image. And we'll put one here of Anacortes. See that that's there and I should be able to say save article. I'll say you failed to submit. Cool. Blob error Vercel access denied, please provide a valid token for this resource.
[00:08:09]
All right, let's go figure out why this is not a valid token. Yeah, so, we are FEM Wiki Masters, we're going to go to the. Yes, so I was in storage, FAM Wikimasters blob prod, the one that I just made. And there's the .env.local here. Under the quick start, you click that and you click copy snippet. And then that's the actual token that we need.
[00:08:55]
I guess that's not, this is not the right one. Maybe we need to restart it. So let's try that again. Okay, do that. Nice picture, Anacortes. And save the article. Okay, now if we just go drop this. There we go. Now we have a nice picture of Anacortes. Are you getting the same, like not allowed? Yeah, where was I supposed to go there in Vercel to get the correct one.
[00:09:16]
This is of everything that I did for Vercel for this entire workshop. This is the part that like, as you see, I have mystified myself again because they've buried it so much. All right, so if you're just on like your base dashboard and you come to storage, and you find blob, prod, whatever you call it, I have a couple of years, so it's this one.
[00:09:44]
You click on it, so we're on like this main dashboard for it. There's this like .env.local right there. And that should give you the correct token. I've had this has happened to me at least 3 times. It has to be called blob read-write token because the SDK specifically looks for that in the environment. So yeah, just click the, you can either click show secret here, and that'll show it, or you can click copy snippet, both of those, and then just put that in your .env here next to your blob base URL.
[00:10:09]
We are at 05 object storage now, so that, this is really all we're going to do with it. The nice thing is that we're using this with Next Image and together with Vercel, it just like does all of your image optimization for you, so it's going to compress things, it's going to make them nice and small for your users, like it does a bunch of stuff for you that you don't, you never have to think about.
[00:10:27]
Vercel just does it for you. It's kind of like their value proposition here, right? I'm showing you images, but this would work for videos, this would work for PDFs, this like object storage is just like a file system, essentially, anything that you want to upload to blob storage, you can. It's called blob because it's unstructured data to them, they don't really care what the data is, they're just storing data.
[00:10:55]
So something that I'm seeing, I'm just going to cover one more time, where to get the variables that you need. One of them is like, if I come to the storage tab, I click on the one that I'm using. It's .env.local right there. So just copy this snippet, and paste it directly in here. I had you put API token in here earlier, that was incorrect, it's read write token.
[00:11:23]
It's important for the SDK that it's called that. The other thing that you need is you need to come to settings, and you need to grab this base URL here, so just copy that. And then put that in this blob base URL here. Okay, why is that important? If you go to your next config, Next.js config, this remote patterns here. Say new URL process.env.blobbaseURL/starstar.
Learn Straight from the Experts Who Shape the Modern Web
- 250+In-depth Courses
- Industry Leading Experts
- 24Learning Paths
- Live Interactive Workshops