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.

1. Creating an OpenAPI Specification (Biggest Win)

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.

What didn't work

This method wasn't without a rocky start. Here are some challenges I encountered prior to settling on the OpenAPI spec approach:

What could work

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.

2. Repository Management and Deployment

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.

What worked

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 didn't work

What worked took 3 projects to perfect. Here are some pitfalls I encountered:

3. Handling Authentication

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.

Use localStorage and Bearer Tokens

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.

Use Cookies with SameSite=None and Secure Flags (on Staging only)

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.

What didn't work

This was another trial-and-error process. Here are some methods I tried that didn't work well: