Lovable builds a working frontend from plain English, and Lovable Cloud wires a native Supabase backend behind it: a Postgres database, auth, storage, Row Level Security (RLS) policies, real-time subscriptions, and edge functions. The trick to a clean full-stack app is order: build and stabilize the frontend first, then connect the backend so the schema fits a settled UI instead of chasing a moving target.

The 24 prompts below are grouped into five stages — connect, auth, data, integrations, and ship. Each one is complete and copy-paste ready. For the fundamentals of prompting this tool, start with our best Lovable prompts, and see the SaaS dashboard pack and how to prompt Lovable for full apps for end-to-end builds.

Advertisement

1. Connect the backend

Turn on Lovable Cloud, model your data, and seed it. Do the schema design once the UI is stable so table shapes match the screens they feed.

1. Enable Lovable Cloud and connect Supabase

Enable Lovable Cloud for this project and connect a Supabase backend. Keep all existing UI, routes, and components exactly as they are — do not restyle or refactor the frontend.

Set up the Supabase project, confirm the database, auth, storage, and edge functions are available, and add the Supabase client to the app. After connecting, show me a short summary of: the project connection status, which environment variables were added, and what is now available (database, auth, storage, functions).

Do not create any tables yet. I will design the schema in a separate step.

Why it works: It scopes the task to connection only and protects a working frontend, so the settled UI drives the backend rather than the reverse.

2. Design the database schema from a data model

Create the database schema in Supabase for this app. Keep the existing UI unchanged; only add the backend tables.

Data model:
- profiles: id (uuid, references auth.users), display_name (text), avatar_url (text, nullable), role (text: 'admin' | 'member', default 'member'), created_at (timestamptz, default now())
- [projects]: id (uuid, pk), owner_id (uuid, references profiles.id), name (text, required), description (text, nullable), status (text: 'active' | 'archived', default 'active'), created_at, updated_at
- [tasks]: id (uuid, pk), project_id (uuid, references [projects].id, on delete cascade), title (text, required), is_done (boolean, default false), due_date (date, nullable), created_at

Relationships: a profile has many [projects]; a [project] has many [tasks].

Requirements: add sensible NOT NULL and default constraints, add indexes on all foreign keys, and enable Row Level Security on every table (I will define the policies in the next step). Show me the migration you generated.

Why it works: It hands Lovable entities, fields, types, relations, and constraints, so the migration is precise instead of guessed.

3. Generate seed and sample data

Add realistic seed data so I can develop and demo against a populated database. Do not change the schema or the UI.

Create a seed script that inserts:
- 3 sample profiles (1 admin, 2 members) with display names and roles
- 5 [projects] spread across the members, with varied statuses
- 20 [tasks] distributed across the [projects], a mix of done and not done, some with due dates

Make the data plausible (real-sounding names and titles, not "test 1"). Ensure all foreign keys line up and the inserts respect existing constraints. Tell me how to re-run the seed and how to reset it.

Why it works: Realistic seed data surfaces layout and RLS bugs that an empty database hides.

4. Plan the backend in Chat mode before building

Use Chat/Plan mode only — do not edit code or run migrations yet.

I want to add [teams and shared projects] to this app. Propose a backend plan covering:
1. The tables and columns you would add or change, with types and relationships
2. The Row Level Security policies needed and who can read/write what
3. Any edge functions required and why
4. Migration order and anything that could break existing data
5. Open questions you need me to answer before building

Keep it concise. When I approve, I will switch to Build mode to implement it.

Why it works: Plan mode is lighter on credits and lets you correct the data model before a single migration runs.

2. Auth & access control

Authentication is where most full-stack bugs hide. Get sign-in, protected routes, RLS, and roles right before you build features on top.

5. Email and password auth with protected routes

Add Supabase email/password authentication. Keep the existing design language; match the current UI styles for any new screens.

Requirements:
- Sign up, log in, and log out flows with inline validation and clear error messages
- On sign up, create a matching row in the profiles table (via a trigger or in code) with role 'member'
- Protected routes: [/dashboard], [/projects], and [/settings] require a session; signed-out users are redirected to /login
- After login, redirect to [/dashboard]; expose the current user and session throughout the app
- A visible sign-out control in the [header]

Do not change any unrelated pages. Show me which routes are now protected.

Why it works: It names the exact protected routes and the profile-creation rule, so auth and your data model stay in sync.

6. Add Google OAuth sign-in

Add "Continue with Google" (Google OAuth) as a sign-in option alongside the existing email/password flow. Keep everything else unchanged.

Requirements:
- Add the Google provider button to both the login and sign-up screens, styled to match the current buttons
- On first Google sign-in, create the profiles row (role 'member') just like email sign-up does, avoiding duplicates
- Handle the OAuth redirect and land the user on [/dashboard]
- Tell me exactly which Google OAuth credentials/redirect URLs I need to configure in Supabase and where to paste them

Why it works: It reuses the existing profile-creation path so both sign-in methods produce identical user records.

7. Write Row Level Security so users see only their own rows

Write and apply Row Level Security policies so each user can only access their own data. Do not change the UI.

For the tables:
- profiles: a user can select and update only their own row (id = auth.uid()); no deletes
- [projects]: a user can select, insert, update, and delete only rows where owner_id = auth.uid(); on insert, force owner_id to auth.uid()
- [tasks]: a user can select/insert/update/delete a task only if its parent [project] is owned by them (join through project_id to [projects].owner_id = auth.uid())

Confirm RLS is enabled on all three tables. Then show me a quick test proving user A cannot read or modify user B's [projects] or [tasks].

Why it works: It spells out the ownership rule per table, including the join-based check for child rows, which is the case people most often get wrong.

8. Roles and permissions (admin vs member)

Add role-based access control using the existing profiles.role column ('admin' | 'member'). Keep the current UI; only gate what is described.

Rules:
- Create a security-definer helper function is_admin() that returns true when the current user's profiles.role is 'admin'
- Admins can select and update every row in [projects] and [tasks]; members keep their existing owner-only access
- Only admins can change another profile's role
- In the UI, show an [Admin] nav link and an [/admin/users] page only to admins; members who hit it are redirected

Implement the role checks in RLS policies, not just in the frontend. Show me the updated policies.

Why it works: Enforcing roles in RLS with a helper function means the rules hold even if someone bypasses the UI.

9. User profile table and settings page

Build a settings page at [/settings] backed by the profiles table. Match the existing design.

The page lets the signed-in user:
- View and edit display_name
- Upload/replace an avatar (store in Supabase storage, save the URL to avatar_url)
- See their email and role as read-only
- Save changes with validation and a success/error toast

Enforce that a user can only read and update their own profile row via the existing RLS policy. Do not add fields that aren't in the profiles table. Show me the final settings component.

Why it works: Constraining edits to existing columns keeps the profile UI and the schema from drifting apart.

10. Password reset and email verification

Add password reset and email verification using Supabase auth. Keep the existing look and feel.

Requirements:
- "Forgot password?" link on the login page that sends a reset email and shows a confirmation state
- A reset-password page that accepts the emailed token and lets the user set a new password with validation
- Require email verification on sign up: after signing up, show a "check your email" screen; block access to protected routes until the email is confirmed
- Handle expired/invalid tokens with clear messaging

Tell me which Supabase email templates and redirect URLs I need to set, and where.

Why it works: It covers the full token lifecycle — send, consume, expire — plus the config you would otherwise discover only when it breaks.

Advertisement

3. Data & storage

With auth in place, wire the features. These prompts cover CRUD, search, uploads, real-time, validation, and optimistic UI — each tied back to the database.

11. Wire a CRUD feature to the database

Connect the existing [Projects] screen to the database. Keep the current UI; only add the backend wiring for CRUD.

For [projects]:
- List: fetch the signed-in user's [projects], ordered by created_at desc
- Create: a form (name required, description optional) that inserts a row; owner_id comes from auth.uid()
- Update: inline or modal edit of name, description, and status
- Delete: with a confirm step; cascade removes the project's [tasks]

Handle loading, empty, and error states, and keep the list in sync after each mutation. Respect the existing RLS policies — do not weaken them. Show me the data layer you added.

Why it works: It maps each UI action to a specific table operation and explicitly forbids loosening RLS to "make it work".

12. Server-side search and pagination

Add server-side search and pagination to the [tasks] list. Keep the existing layout.

Requirements:
- A search box that filters [tasks] by title (case-insensitive, matches partial words), querying the database — not filtering an already-loaded array
- Page size of 20 with "previous/next" (or infinite scroll), using Postgres range/limit so we never load the whole table
- Optional filters: status (done / not done) and due date range
- Debounce the search input and show a subtle loading indicator during fetches
- Add a database index that supports the title search

All queries must respect existing RLS. Show me the query and the index.

Why it works: Pushing search and paging to Postgres keeps the app fast as data grows and prevents leaking rows the client shouldn't see.

13. File and image upload to Supabase storage

Add file uploads to [tasks] using Supabase storage. Keep the existing design.

Requirements:
- Create a private storage bucket [task-attachments]
- Each [task] can have multiple attachments; store metadata in a new table [task_files]: id, task_id (references [tasks], cascade), file_path, file_name, mime_type, size_bytes, uploaded_by (auth.uid()), created_at
- Upload UI on the task detail view: accept images and PDFs up to 10 MB, show progress, list attachments with download links
- Storage policies and RLS on [task_files] so a user can only upload to and read attachments of [tasks] within their own [projects]
- Generate signed URLs for downloads rather than making the bucket public

Show me the bucket policies and the [task_files] RLS.

Why it works: Pairing a metadata table with a private bucket and signed URLs is the pattern that keeps uploaded files access-controlled.

14. Real-time updates with subscriptions

Make the [tasks] list update in real time using Supabase real-time subscriptions. Keep the UI unchanged except for live updates.

Requirements:
- Subscribe to inserts, updates, and deletes on [tasks] for the currently viewed [project]
- When another session changes a task, reflect it in the list without a manual refresh
- Only receive events the user is allowed to see (real-time must respect RLS)
- Clean up (unsubscribe) when the component unmounts or the [project] changes to avoid leaks
- Handle reconnects gracefully after the connection drops

Show me the subscription setup and cleanup.

Why it works: It calls out RLS-aware channels and unsubscribe cleanup, the two things that make real-time either secure or leaky.

15. Form validation tied to database constraints

Align client-side form validation with the database constraints for the [project] and [task] forms. Keep the existing UI.

Requirements:
- Mirror DB rules in the form: required fields (name/title), max lengths, allowed status values, valid date formats
- Add matching CHECK constraints in the database where they are missing (e.g. name length 1–120, status in the allowed set) so bad data can't be inserted even outside the UI
- Show field-level errors and block submit until valid
- If the database still rejects an insert (e.g. a race or constraint), surface a readable error instead of a raw Postgres message

Show me the added CHECK constraints and the validation schema.

Why it works: Validating in both the form and the database means the constraint holds no matter how the row is inserted.

16. Optimistic UI on create and update

Add optimistic UI to the [task] create and "toggle done" actions so the interface feels instant. Keep the existing design.

Requirements:
- On create: show the new [task] in the list immediately with a pending state, then reconcile with the server response
- On toggle done: flip the checkbox instantly, then confirm with the database
- On any failure: roll back the optimistic change, restore the previous state, and show an error toast
- Prevent duplicate rows if the request is retried
- Keep this consistent with the existing real-time subscription so updates don't fight each other

Show me the create and toggle handlers.

Why it works: It names rollback and the real-time interaction, so the "instant" UX doesn't produce ghost or duplicate rows.

4. Integrations & functions

Anything with a secret — external APIs, LLMs, Stripe, email — belongs in an edge function. These prompts keep keys server-side and off the client.

17. Connect an external API with a secret via edge function

Integrate [external API name] and keep its API key server-side. Do not expose any key in client code.

Requirements:
- Store [EXTERNAL_API_KEY] as a Supabase/Lovable secret; tell me exactly where to paste it
- Create an edge function [fetch-external-data] that reads the secret, calls [external API endpoint], and returns only the fields the app needs
- The frontend calls the edge function (never the third-party API directly)
- Require an authenticated session to invoke the function; validate inputs and handle upstream errors/timeouts with clear responses
- Add basic rate limiting or an abuse guard if the endpoint is costly

Confirm the key never appears in the client bundle. Show me the edge function.

Why it works: It makes the secret-in-a-function pattern explicit and asks Lovable to confirm nothing leaked into the client bundle.

18. Add an AI feature (call an LLM from an edge function)

Add an AI feature that [summarizes a project's tasks into a short status update]. Keep the existing UI; add one button and a result panel.

Requirements:
- Create an edge function [ai-summary] that reads the LLM API key from secrets, gathers the [project]'s [tasks] (only if the caller owns the project), builds a concise prompt, calls the model, and returns the summary text
- Never expose the API key or call the model from the browser
- Require an authenticated session; verify project ownership inside the function before reading tasks
- Handle model errors, timeouts, and empty input; show a loading state and a readable error
- Cap input size so a huge project doesn't blow the token budget

Show me the edge function and how the frontend invokes it.

Why it works: The ownership check inside the function stops the AI endpoint from becoming a way to read data past RLS.

19. Stripe checkout and webhook to mark orders paid

Add Stripe payments for [Pro plan upgrade]. Keep the existing pricing UI; wire the backend only.

Requirements:
- Store the Stripe secret key in secrets; tell me where to paste it and which price ID to use
- Edge function [create-checkout]: creates a Stripe Checkout session for the signed-in user and returns the redirect URL
- Edge function [stripe-webhook]: verifies the Stripe signature, and on checkout.session.completed, marks the user's [orders]/[subscription] row as paid and updates profiles accordingly
- Add the [orders] table if needed: id, user_id, stripe_session_id, amount, status ('pending'|'paid'), created_at, with RLS so users see only their own orders
- Never trust the client for payment status — only the verified webhook flips status to 'paid'

Tell me the exact webhook URL to register in Stripe. Show me both functions.

Why it works: Marking orders paid only from a signature-verified webhook is the rule that prevents users from faking a successful payment.

20. Send transactional emails

Add transactional emails via [email provider, e.g. Resend]. Keep the API key server-side.

Requirements:
- Store [EMAIL_API_KEY] in secrets; tell me where to paste it and how to set the sender domain
- Edge function [send-email] that sends templated emails and is called from other functions/flows, not directly from the browser
- Trigger a "welcome" email on sign up and a "[project] shared with you" email when relevant
- Include plain-text and HTML versions, handle send failures without blocking the main action, and log failures
- Do not send duplicate emails on retries (use an idempotency key)

Show me the edge function and where it gets triggered.

Why it works: Routing email through one server-side function with idempotency avoids exposed keys and duplicate sends on retry.

21. A scheduled or background job

Add a scheduled job that runs once a day and [emails users a digest of tasks due today]. Keep the app UI unchanged.

Requirements:
- Create an edge function [daily-digest] that, per user, finds [tasks] with due_date = today in their [projects] and sends a digest via the existing [send-email] function
- Schedule it to run daily at [08:00 UTC]; tell me exactly how to configure the schedule (cron/Supabase scheduled function) and where
- The function runs with elevated access but must scope every query to the correct user; never leak one user's tasks to another
- Make it idempotent so a re-run on the same day doesn't double-send
- Log a summary (users processed, emails sent, errors)

Show me the function and the schedule configuration.

Why it works: A background job runs without a user session, so the per-user scoping and idempotency instructions prevent both leaks and double-sends.

5. Harden & ship

Before launch, add observability, review your security surface, and get the app onto a real domain with version control.

22. Add error handling and logging

Harden error handling and logging across the app and edge functions. Keep the UI, but improve failure states.

Requirements:
- Wrap data fetches and mutations so every failure shows a readable message (never a raw Postgres/Stripe error) and offers a retry where sensible
- Add a top-level error boundary so a component crash doesn't blank the whole page
- In edge functions, catch errors, return structured JSON error responses with safe messages, and log server-side details (including a request id) without leaking secrets or PII
- Add lightweight logging around auth failures, payment webhooks, and background jobs
- List anything currently swallowing errors silently and fix it

Show me the error boundary and the edge-function error pattern.

Why it works: It separates safe user-facing messages from detailed server logs, which is what makes production issues debuggable without exposing internals.

23. Run a security review of RLS and exposed keys

Run a full security review of this app before I ship. Do not change behavior yet — report findings first.

Check and report:
1. Every table: is RLS enabled, and do the policies actually restrict rows to the right users (test cross-user access)?
2. Any table exposed with no policy or an overly-permissive "true" policy
3. Any API key, secret, or service role key referenced in client-side code or the bundle
4. Edge functions: do they verify the session and re-check ownership before reading/writing data?
5. Storage buckets: private vs public, and whether policies match intent
6. Stripe/webhook: signature verification present and payment status only set server-side

Give me a prioritized list (critical/high/medium) with the exact fix for each. I will approve fixes before you apply them.

Why it works: It turns the built-in security scan into a concrete checklist and forces a human approval step — the review the spec recommends for sensitive data.

24. Connect GitHub and deploy to a custom domain

Prepare this app for production: connect GitHub and deploy to a custom domain.

Requirements:
- Set up GitHub two-way sync for this project and tell me which repo/branch it uses
- Confirm all secrets and environment variables are set for production (list them, values hidden)
- Walk me through connecting the custom domain [example.com], including the exact DNS records to add and how to verify SSL
- Confirm the production Supabase project has RLS enabled everywhere and that migrations are applied
- Give me a short pre-launch checklist (auth flows, payments in live mode, error monitoring, backups)

Do not put anything sensitive into the repo.

Why it works: It ties version control, environment config, DNS, and a launch checklist into one pass so nothing gets missed at go-live.

Work these in order and keep each prompt to one scoped task. For quick reference while you build, keep the Lovable prompt cheat sheet and prompt templates open in another tab, and revisit our best Lovable prompts when you start a new feature.

Frequently Asked Questions

Does Lovable have a backend?

Yes. Lovable Cloud wires a native Supabase backend — Postgres database, auth, storage, Row Level Security policies, real-time subscriptions, and edge functions — all from plain English, alongside the React and Tailwind frontend.

What is Lovable Cloud versus Supabase?

Lovable Cloud is the layer that provisions and manages a Supabase project for you from plain English. Supabase is the underlying platform providing the Postgres database, authentication, storage, and edge functions. Lovable Cloud writes the schema, RLS policies, and functions on top of Supabase.

How do I add login and auth to a Lovable app?

Ask Lovable to enable Supabase auth with email and password, add protected routes that redirect signed-out users to the login page, and expose the current user in your app. You can also add Google OAuth. Lovable handles sessions and the auth UI.

What is Row Level Security and why does it matter?

Row Level Security (RLS) is Postgres enforcing per-row access rules at the database, not just in your UI. Without RLS, any authenticated user can read or edit every row. With RLS, a policy such as user_id = auth.uid() guarantees users only touch their own rows, even if the frontend has a bug.

How do I use API keys in Lovable without exposing them?

Store external API keys (OpenAI, Stripe, and so on) in Lovable or Supabase secrets and call them from an edge function. The key stays server-side and is never shipped to the browser. Never paste keys into client code — automated scans flag exposed keys.

Can I add Stripe payments to a Lovable app?

Yes. Lovable integrates Stripe checkout and handles webhooks through an edge function. Ask it to create a checkout session from an edge function and add a webhook that marks orders paid when Stripe confirms payment. The Stripe secret key lives in secrets.

Is the generated backend production-ready and secure?

It gets close, but review it. Lovable runs automated security scans that flag exposed keys and weak RLS. For anything sensitive, get an independent security review, confirm every table has RLS enabled with correct policies, and test that users cannot read other users' data before you ship.

Advertisement