Claude Code Tutorial: Add AI to Your SaaS App (AI SDK) β
How to Build Full-Stack AI SaaS with Claude Code (Tutorial)Freshπ
2025-11-17
Integration Flow β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INTEGRATION ARCHITECTURE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β USER REQUEST β
β β β
β βΌ β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β β βββββΊ β β βββββΊ β β β
β β Google β β OpenAI β β API β β
β β β βββββ β β βββββ β β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β β β β
β β β β β
β ββββββββββββββββββββββββββ΄ββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββ β
β β RESULT β β
β βββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββIntegration Points β
- Core concepts explained
- Step-by-step implementation
- Practical examples
Transcript β
[00:00] In this video, I'll show you how to use Claude Code to add AI functionality to our application. In this series, I'll show you how to build a complete SaaS app using coding agents like Claude Code. This includes everything from user authentication, data persistence, all the way to payment processing. So if you wanted to follow along, definitely check out the full playlist in the description of the video. So far, we've created all of the UI pages and components for our application. We also added user authentication
[00:30] so users can sign in and out using their Google account. We also added a Postgres database for data persistence. And we can also see the different tables in our database, which at the moment only contains our user details. So let's continue working on this app. When we go to the generate page, we want to allow users to upload images of themselves or their pets. They should then be able to use their credits to generate classified versions of themselves. Now in order to generate these images, we will be using
[01:01] Google's nano banana model. You can actually try this model yourself by going to aistudio.google.com, then click on playground, then click on nano banana. So now we can pass in a prompt like create an image of a banana in a suit. Let's send this. And now we have an image of a banana in a suit. Now what we'll be using this for is simply create a new chat, we'll upload an image, and then we'll provide a very specific prompt to
[01:31] convert the subjects in the image to plushies. I actually used Claude to help you come up with this prompt. So if you want, you can pause the video to get this exact prompt. So I'm going to copy all of this and then paste it into here. Let's send this. And that gives us a result like this. Cool. So we'll effectively use the exact same prompt in our actual application. How do we bring this behavior into our application? Now there are basically two ways to do this. The simplest solution
[02:02] without a doubt is simply to use the Gemini SDK directly. At Google makes it extremely easy actually. So once we have a working solution, what we can do is go to get code, then select TypeScript. So this gives us the exact code snippet we need to pass the image to the SDK, how to pass in the prompt, and how to receive the generated image. So then what we can do is copy this code and ask Claude Code to implement the solution for us. Of course, the only other thing you'd
[02:32] have to do is generate an API key. So you have to go to get API key and create a key and store it in your environment variables. Now this approach will work perfectly fine, but there is one limitation that you have to be aware of. By calling the Google SDK directly, we are kind of locked into the Google ecosystem. What happens if another model comes out that's even better than Nano Banana, and now we want to migrate our app over to using that new model. That means we have to replace all of this code with the SDK or
[03:05] the API from it other provider. So let's assume then that this is our app, and in order to generate the images, we'll call the Google SDK directly. But let's say OpenAI releases a model that's even better than Nano Banana for image editing. Now what we'd have to do is replace all of the code that we've built and replace it with an OpenAI SDK. The SDKs and APIs between these different providers can look very different, and this migration can actually mean major changes
[03:35] to your app. So what I like to do is to use the AI SDK. Now the AI SDK really simplifies things. It creates a single interface that your app can call irrespective of what provider you plan to use. It's abstracting away all of the complexities of calling these different providers. So all you have to do is say well, I actually want to call OpenAI, and the AI SDK will route your request to OpenAI. Or if you ever wanted to change that, you can just say
[04:06] hey instead go ahead and call Nano Banana from Google, and the AI SDK will do that routing for you. Your app does not have to change. And truth be told, this is already a really good solution for production ready applications. Now there are many reasons why I like the AI SDK, and I can actually create a dedicated video on it. I've tried every framework out there, and at first I use Lang chain for a lot of my projects. And recently I've just been using the AI SDK without any issues, especially when it comes to
[04:38] dealing with structured data. Right, so this solution will be absolutely perfect for 99% of applications out there. So this column over here is actually called the providers, and in here I'm just going to call this the SDK. So let's say we wanted to give our users the option to select which model they wanted to use. So they could select Nano Banana, or we could give them options from other providers as well. The challenge with the stick stack is we'll have to store the API keys for each of these providers
[05:10] in our environment variable file. And since all of these are paid services, we'll have to load credits onto our OpenAI account, and we'll load credits onto our Gemini account. And the same thing for all the other providers in our application. So this can get really messy if we plan to offer multiple providers in our app. So one way to simplify this even more is to use Open Router. So basically we'll use Open Router as the service provider, and Open
[05:42] Router gives us access to all of these different services, all under one single API key and one single account. So if you're unfamiliar with Open Router, you can go to openrouter.ai, and here you can see all the models that's available. Currently they're offering over 500 models from all the major service providers. And yes, they do simplify things because you only add credit to this one account, and you only use a single API key. And that will give you
[06:12] access to pretty much any model you can imagine. Now as with anything in life, there's always pros and cons to everything. If you call these providers directly, then you will purchase these credits directly from these providers. So there's no markup or additional fees that you have to worry about. Now if you're using Open Router, the pricing is slightly different. Apparently they don't add a markup on the actual provider costs, but they do charge you a fee when you load credit onto your account. Right, now we've had
[06:43] a look at a few ways in which we can add AI capabilities to our application. If you follow the setup video in the series, then you already have the AI SDK and Open Router setup in this project. So if we go to the package.json file, we can go to dependencies, and here we can see the AI SDK, and we're currently using version 5. And we can also see that Open Router for the AI SDK has already been installed as well. Right, and looking at Cloud Code, if we pull up
[07:14] our MCP servers, we can see that we currently have context 7 setup as well. And of course in our docs folder, we can go to technical, AI, and I've added some documentation related to the AI SDK. So let's go ahead and add our AI functionality to our app. So I'm going to ask Cloud Code to continue working on this generate page. So the first thing I'll do is go to plan mode, and it's a, hey there, let's create an implementation plan for the following.
[07:44] On the generate page, we're able to upload an image, but we have no way of generating the images for this application. Now what we want to do is add the capabilities for the user to upload an image, then when I click on generate, it should use one of their credits, and we will then use an AI model to create a classified version of the subjects in that image. Now for the tech stack, we will be using the AI SDK, as well as Open Router
[08:15] as the provider for generating these images. So what I want to do now is just also give it the name of the model. So we can say the name of the model is, and now we have to get the name. Nano Banana is just kind of a nickname for the model, but the actual model name is Gemini 2.5 Flash Image. In fact, we actually have to get it from Open Router if you are using Open Router. If you're simply using the Google SDK directly,
[08:45] then really all you have to do is copy the sample code and give it to Cloud Code at this stage. But if you're following along, simply go to Open Router, and let's type in Nano Banana, and now we can click on this guy. Then let's copy this text and paste it into the chat. Please create a Next.js server action for generating this image. This server action should be protected because any authorized users should be able to
[09:15] generate images. If a user has insufficient credits, they should not be allowed to generate images. Instead, we should show an image on the screen using Sonar or a Toast message saying that the user has insufficient funds and they need to purchase additional credits. All right, so for this credits field, I just want to show you, we actually added this in the previous video. So in the user table, if we scroll to the right, we can see this credits field. So really,
[09:46] if you don't have something like this yet, you can simply ask Cloud Code to add a credits field to your user profile. So another thing I want to do is actually persist these images in storage. Because what's going to happen is the user is going to generate the image, and when they refresh the page, it's gone. We're not storing the actual generated image anywhere. All right, so I also want you to persist these images in Blob Storage. We've got access to Vercel's
[10:17] file storage. So store the original image and the generated images in Blob Storage. In our .env file, we've got this variable, Blob_Retrite_Token. We can use this for file storage. So from Vercel, let's go to storage, then click on create database, select Blob, continue, and give it any name you want, like Placify or whatever. Let's create this. Then under .env.local, let's copy this and add it to
[10:51] our .env file and save your .env file. Cool. Our app is now able to store files. How easy was that? And I think we've almost got everything. We also have this gallery page. So it would be cool if we can view our generations in this gallery page. And finally, we also want to update the gallery page. So these generated images should be viewable in the gallery page. That also means we want to give users the ability to delete images from the
[11:22] gallery as well. What would be really cool is if you could add some sort of slider effect so people could view the before and after of the generated image. All right, I think that's all. Let's send this. Remember, we're in planning mode so the agent won't start any work until we've signed off this design. This is a cloud code feature that I absolutely love. So it will ask us these clarifying questions before simply coming up with a plan. How should we use Google Gemini to generate
[11:52] Placified images? Should we use it to analyze the uploaded image and then generate a new Placified version or pass the image directly with a prompt? Now, this is really cool. I actually wouldn't have thought about this in the first place. I'll go with option two. We can always change it if we don't like the results. What should happen after a successful image generation? I'll select option one. Should we show a confirmation dialog? Yes. How should we handle the gallery? So we just show everything or paginate it. Let's do
[12:23] paginate it. Let's submit the answers and let's go. Now, I'm just going to stop this generation for a second. What I forgot to add was additional context on generating images using the AI SDK. Getting this documentation is really easy. I'll just Google something like the AI SDK image generation. Then we can go to the AI SDK docs and now we have detailed docs on using the SDK for generating images. So I'm going to copy this page and in our docs folder on the technical AI,
[12:56] let's create a new file called image generation dot MD. Then let's chuck it in there. Cool. Now agents can also use MCP servers like context seven to retrieve up-to-date documentation itself. Now, as I explained in the previous video, there are certain limitations with using MCP servers, especially if you want to use cloud code web. So sometimes storing the documentation locally in a docs folder can yield even better results. And of course, as a developer,
[13:27] it's useful to have a look at the documentation yourself to get an understanding of what the solution actually does. So for this, I'm just going to pull in this file and say, I forgot to give you this. Here is the documentation on generating images using the AI SDK. You can also use the context seven MCP server to retrieve up-to-date information on generating images using the AI SDK and open router. All right, cool. Let's see this.
[13:59] Right. So apparently we've got our implementation plan. So I highly recommend going through this implementation yourself before continuing. Right. So I just went through the implementation plan and it looks good to me. Now, as I showed you in the previous video, we'll store this implementation plan in our project folder. So instead of using something like spec kit or bmat, all we really have to do is call this create feature prompt. This is a command that I've already given to you for free in the setup video. So let's empty run
[14:31] this command. And really all this is going to do is create a sub folder for this new feature in the specs folder. In fact, it just popped in right now. And within the sub folder, we'll get two files, the requirements document and the implementation plan. If you want to see my exact workflow for planning and implementing features using cloud code, then definitely check out the previous video in the series, which I'll link to in the description. All right. So now in this folder, we've got our implementation plan, which gives the entire solution
[15:02] in phases with actionable tasks per phase. And what's cool is we'll get cloud code to mark these tasks as done as it's working through the solution. So that way we can track progress or continue with the implementation, even if we had to close cloud code. Then in the requirements file, we basically have the original requirements along with all of those decisions that we made. Okay, cool. Back in cloud code, I'm going to clear the conversation to free up some context. And now I'm simply going to grab in this feature folder and say, so let's
[15:36] have a look at this implementation plan for a second. I can see there's actually a lot to do here. And we do want to keep our context windows as small as possible. So it might overwhelm the agent if we ask you to implement everything in a single go. So let's try to maybe implement the first four phases and see how it goes. Hey there, please could you implement phase one to four, then once you're done, mark the tasks as complete in the implementation plan. All right, I'm just
[16:06] going to make sure that we've got thinking mode on. And then let's send this. All right, so while cloud code is running, I'm just going to do some house cleaning. I'm just going to copy this snippet again. And let's add this to our production instance. So I'll go to my production project, let's go to settings, environment variables, let's add that environment variable and click on save. Cool, cloud is done. And if you have a look at the implementation plan, we can see that the tasks have been marked as complete. And we're
[16:38] ready to move on to phase five. Now what I'm going to do is just run the context command. And we're already sitting at 60%. Perfect. I typically don't like to go over 60% or maybe 70% pushing it. But the more tokens you use, the worse the results will start to get. So what we'll do instead is run the clear command. And now we have a clean context window. And because we have this implementation plan, what we have to do is grab this folder again, and say, well, let's just see how many phases we have left. We have phase five,
[17:10] six, seven, and eight. Actually, I'm just going to risk it. Let's say, please implement the remaining phases. Let's make sure we've got thinking on, and let's send this. Alright, so cloud code finished implementing all of these phases. And what I like to do is to actually grab this folder again, and then ask cloud code to do a code review. Hey there, we just completed implementing all of these changes. Please can you do a thorough code review and make any improvements along the way.
[17:42] Alright, so now that we're done with all of these changes, there is something I like to do. We're going to just ensure that our database is up to date. So let's run npm run DB generate, then let's run npm run DB migrate. And then let's see if this actually works. Okay, let's upload an image. And of course, we can't do anything because we don't have any credits. As you can see, we currently have zero credits. And we haven't implemented the payment system yet. So what
[18:14] we'll do is simply go to our database table. And let's go to the credits field, exchange this to 200 credits, let's save this. And if I refresh our app, I still only see zero credits. So that's because we really only focused on implementing the AI functionality. And the app is still using dummy data for the credits. We don't need a dedicated implementation plan for this. Alright, please can you help with a bug. I've changed the credits against my user
[18:45] profile to about 200 credits. But in the app, it's still showing zero credits. So I suspect we still have to use the actual value from the database in our application. So please can you ensure that the credit related information is actually working. Alright, cool, the changes are done. And we can see the credits now in the top nav bar, we can see them on the screen. And if we go to our dashboard, we can see the credit count as well. So let's try to generate our first image.
[19:16] Let's click on create plushie. Alright, so we're getting this loading spinner and the message saying creating your plushie. And of course, we get this error message. So I'm just going to clear the chat again. And in order to troubleshoot these issues, what I like to do is to go to our dev server and see if we can find any errors. So I'm just going to copy all of this. Alright, so I tried to generate the image and I actually got an error message back. This is what I can see in the terminal. Remember
[19:47] to reference the AI SDK documentation and use context seven to retrieve up to date documentation on using the AI SDK, along with open router for generating images. Alright, I'll just paste in the text from the terminal. And let's send us are still having issues with getting the image generation to work. If you find yourself in that situation, ask cloud code to add some logic to help it debug the issue. So it could maybe write some stuff to
[20:17] logs or to the terminal. So Claude said it just added some debugging to see what's actually happening. And I was asking me to try and regenerate again. So fine, let's refresh this app. Let's load our image is pick on generate plushie. Now this will fail, but hopefully this will give Claude code way more context to work with. So I'll just copy everything from the terminal and paste it into the chat. And I'll just continue with this process until the image generation works. Alright, so I've had a bit of a back and forth with the agent to
[20:49] resolve all of the issues, simply by sharing any error messages from the terminal with the agent. And it seems to be working already used one credit. So I'm just going to run it again. It shows the screen where it's all generating the plushie and done we've got our image. So we also have the slider we can slide back and forth to view the before and after and we have options to download the plushie, which actually seems to work. I'll just put it into this screen. So that's
[21:19] awesome. And we can also go to the gallery where we can share our previous generations. The first one actually looked really creepy. So it's something like this. We can definitely get the agent to refine the prompt as we work on this. Let's actually delete this image to see if the delete functionality works, which it does. And if we have a look at our database, we can see the one generation every year. And we can see the credits were updated as well. But at this stage, I'm happy
[21:51] with this image generation logic. So it won't make sense to take a snapshot at this stage. Now there's one thing that's been bugging me though. We haven't updated the claud.md file yet. And it still contains all of the boilerplate stuff. So besides for the tech stack, this app has changed quite a lot. So I'm actually going to clear this file completely. And back in cloud code, let's run the init command. Cloud code will now analyze our project and all of our features and update the claud.md file accordingly. Right,
[22:22] awesome. Now that the claud.md file is up to date, we're ready to deploy these changes to production. So I'll run my check bold command. This will simply run linter and type check and the npm bold command and resolve any issues like syntax errors along the way. Cool. And now that our code is clean, let's run the checkpoint command. And this one, I'll take all of these untracked changes. And we've actually done a lot of work so far. It's going to add all
[22:53] of these untracked files to a commit with a detailed description or comment. Like so, all of these files have now been added to a commit. Cool. Let's take on sync changes. I just want to push all of these changes to production. If you enjoyed this video, then please hit the like button and subscribe to my channel for more Claude code and the agentic coding tutorials. Let me know down in the comments if you've got any questions related to the series. I'll see you in the next one. Bye bye.