When I first discovered Lovable, I was drawn to its promise of rapid frontend development. But like many developers, I have a custom backend I'm not willing to part with, one that gives me the security and scalability I need. So, I embarked on a journey to connect the two. It wasn't always a straightforward path. There were moments of seamless integration and moments of frustrating roadblocks. In this post, I'll walk you through the highs and lows of that process - what worked, what didn't, and the key lessons I learned along the way to finally create a smooth and efficient workflow.
The biggest win in my integration journey was figuring out that AI does well with OpenAPI specifications. It is a machine-readable document that describes your backend API, including endpoints, request/response formats, authentication methods, and more. Think of it as a contract between your frontend and backend, ensuring both sides understand how to communicate effectively.
If you already have a specification, simply copy your openapi.yml or openapi.json file into the root of your Lovable project.
Though, if you are not a great documenter, you can use an AI Code Agent like Claude Code or GitHub Copilot Chat to generate one from your existing backend code. Here's a sample prompt:
Extract the OpenAPI specification from the attached files and output it as a single openapi.yml file. Ensure that objects are defined in the components section and referenced appropriately. Include all endpoints, request parameters, and response schemas. The specification should be comprehensive enough for a developer to implement the API without additional context.
Remember to attach your backend code files when running this prompt.
Once you have the openapi.yml file in your Lovable project's root, you can generate a TypeScript API client. Run the following prompt, modifying the URL to your backend:
Interpret the openapi.yml file in the root of this project and generate a typescript API client in `lib/api.ts`. Include all schemas as types and interfaces. The client should have functions for each endpoint with appropriate parameters and return types. Use fetch for making HTTP requests and handle errors gracefully. Ensure the code is clean, well-documented, and follows best practices. The backend URL is https://api.example.com
This generates an API client at lib/api.ts that you can use to interact with your backend service. To ensure that Lovable always use the API client, you should add the following the "Knowledge" section of your Lovable project:
The API client is located in lib/api.ts and should be imported to fetch any data from the backend.
This method wasn't without a rocky start. Here are some challenges I encountered prior to settling on the OpenAPI spec approach:
What I didn't try was to directly generate the API client from the backend codebase using tools like Swagger Codegen or OpenAPI Generator. I didn't opt in for this because I wanted to keep my client simple. Not much hallucinations happened when I used the AI generated API client.
A common problem is having to manage 2 repositories - one for the backend and one for the Lovable frontend. This led to a lot of problems when deploying because I had to remember to deploy both repositories separately.
To keep my backend and Lovable frontend in sync, I added the Lovable GitHub repository as a submodule to my backend project. This creates a pseudo-monorepo setup, where your backend code lives in the root of the repository and the Lovable frontend lives in a subdirectory. This makes it easier to manage both codebases and coordinate changes.
To add the submodule, run these commands from your backend project's root directory:
git submodule add https://github.com/choyiny/project-ui.git git submodule update --init --recursive
Now, your project structure will look something like this:
/my-backend-project /project-ui (Lovable submodule)
Since I use Cloudflare Workers, I set up a simple build script to copy the Lovable frontend's generated files to my backend's public directory during deployment. Here’s a sample script to automate this:
#!/bin/bash # Navigate into the Lovable project submodule cd project-ui # Pull the latest changes git pull origin main # Install dependencies and build the frontend npm install npm run build # Remove the old public directory and copy the new build files rm -rf ../public mkdir -p ../public cp -r dist/ ../public
This assumes your directory structure is:
/my-backend-project /project-ui (Lovable generated submodule) /dist (generated frontend files) /public (backend's public directory)
For those unfamiliar with Cloudflare Workers, you can deploy both static files and serverless functions in one place. The static files go into the public directory, while your backend logic can be handled by Workers. With hono, you can easily serve static files alongside your API routes:
const app = new Hono<{ Bindings: Bindings }>(); // your API routers app.route("/api/users", usersRouter); // Serve static files from the public directory app.get("*", async (c) => { return c.env.ASSETS.fetch(c.req.raw); }); export default app;
What worked took 3 projects to perfect. Here are some pitfalls I encountered:
One of the best features of Lovable is its instant preview. However, if your backend requires authentication, you need to ensure your Lovable frontend can handle it within the preview environment, which is typically an iframe. Some methods, like "Login with Google" or one-time links, can be challenging here. I found two reliable ways to handle this.
This is the simplest way to manage authentication with Lovable. After a user logs in, you can store a Bearer token in localStorage. Then, modify your lib/api.ts client to automatically include this token in the Authorization header of all your API requests. This approach works well and is straightforward to implement.
If you need to use cookies for authentication, set them with the SameSite=None and Secure flags. This allows the browser to send the cookies in cross-site requests, which is essential for Lovable's iframe environment.
Be extremely careful with this approach, as it can make your backend vulnerable to Cross-Site Request Forgery (CSRF) attacks. It's best to use this method only with your staging API and never with your production API. You can mitigate this risk by using anti-CSRF tokens if your backend framework supports them.
This was another trial-and-error process. Here are some methods I tried that didn't work well:
lib/api.ts, as I had to handle both real and mocked authentication flows.\

