Connect Lovable to an existing MySQL database by creating a Supabase Edge Function that uses PlanetScale's serverless HTTP driver or a lightweight REST API wrapper. Store your MySQL credentials in Cloud → Secrets, proxy queries through the Edge Function with parameterized statements to prevent SQL injection, and call the function from your Lovable React frontend. PlanetScale's serverless driver is the cleanest path because it works natively with Deno's fetch-based networking.
Connect Lovable to your existing MySQL database for legacy data access
MySQL powers an enormous percentage of the world's web applications — from WordPress sites to e-commerce platforms to custom business applications. If you are rebuilding a frontend in Lovable while keeping your existing MySQL database, or if your business logic and historical data live in MySQL and migration is not yet practical, this integration gives you a working bridge between Lovable's React frontend and your MySQL data.
Lovable has no native MySQL connector. The integration uses Lovable's standard pattern for authenticated external databases: credentials stored in Cloud → Secrets, all queries proxied through Supabase Edge Functions. The specific approach depends on where your MySQL is hosted. For PlanetScale (a serverless MySQL platform popular in modern web development), the integration is clean and straightforward: PlanetScale provides a serverless HTTP-based driver specifically designed for Deno and edge environments that works without any TCP networking. For other MySQL hosts — AWS RDS, Google Cloud SQL, DigitalOcean Managed Databases, or self-hosted servers — you need a lightweight REST API proxy layer because Deno does not support the TCP-based MySQL protocol.
The trade-off compared to Lovable's native Supabase is the same as with all non-Supabase databases: you lose AI-assisted schema generation, auto-created RLS policies, real-time subscriptions, and natural language database operations. However, for teams with significant existing MySQL investments, this integration provides a functional path to building modern Lovable interfaces on top of existing data.
Integration method
MySQL integrates with Lovable through Supabase Edge Functions that query the database via PlanetScale's serverless HTTP driver (for PlanetScale-hosted databases) or a REST API proxy (for other MySQL hosts). MySQL credentials are stored in Cloud → Secrets and accessed via Deno.env.get(). All queries use parameterized statements, and the Edge Function acts as the sole bridge between the Lovable frontend and your MySQL data.
Prerequisites
- A Lovable account with an active Lovable Cloud project
- A MySQL database accessible over the internet (PlanetScale, AWS RDS, Google Cloud SQL, DigitalOcean, or self-hosted with public access)
- For PlanetScale: a PlanetScale database with a service token or password created for API access
- For other MySQL hosts: either a REST proxy deployed in front of MySQL, or MySQL credentials and the database's public hostname
- A list of the specific tables your Lovable app will query
Step-by-step guide
Choose your MySQL connection approach: PlanetScale driver vs. REST proxy
Choose your MySQL connection approach: PlanetScale driver vs. REST proxy
Before writing any Edge Function code, you need to choose the right connection method for your MySQL host. The choice matters because Deno's runtime environment handles networking differently from Node.js. Option A — PlanetScale serverless driver: If your MySQL database is hosted on PlanetScale, you can use the @planetscale/database package, which is specifically designed for HTTP-based environments like Deno and Cloudflare Workers. It communicates with PlanetScale's HTTP API rather than over TCP, making it the cleanest integration for Deno Edge Functions. To get started, log in to app.planetscale.com, select your database, go to Settings → Passwords, and create a new password. Note your host, username, and password. Option B — REST proxy for other MySQL hosts: If your MySQL is on AWS RDS, Google Cloud SQL, a self-hosted server, or any other provider that requires TCP connections, you need a REST proxy in front of MySQL. This is a small Node.js Express application that accepts HTTP requests and translates them to MySQL queries using the mysql2 package. Deploy this proxy on any Node.js hosting (Railway, Render, Fly.io, or Azure App Service) and note its public URL and API key. Option C — PlanetScale import: If your current MySQL is on another host, consider importing it to PlanetScale. PlanetScale offers a free import wizard that copies your existing MySQL data and sets up ongoing replication. This is the path of least resistance for getting a Deno-compatible MySQL connection. This guide focuses on Option A (PlanetScale) for the code examples, with Option B noted where the approach differs. Choose based on where your data currently lives.
Pro tip: PlanetScale's serverless driver eliminates the need for a proxy server entirely — if you have flexibility in where you host your MySQL, PlanetScale is the simplest path for Lovable integration.
Expected result: You have chosen a connection method and have either: (A) your PlanetScale database host, username, and password ready, or (B) a REST proxy deployed with a public URL and API key.
Store MySQL credentials in Cloud → Secrets
Store MySQL credentials in Cloud → Secrets
Store your MySQL access credentials in Lovable's Cloud Secrets panel. Whether you are using PlanetScale directly or a REST proxy, the credentials must never appear in your frontend code, Git repository, or Lovable chat history. Lovable's security infrastructure blocks approximately 1,200 hardcoded API keys per day and holds SOC 2 Type II certification — but the safest practice is always using Secrets from the start. To access the Secrets panel, click the '+' icon at the top of the Lovable editor next to the Preview label. In the Cloud panel, click the 'Secrets' tab. Click 'Add new secret' and add your credentials. For PlanetScale (Option A), add: - Name: MYSQL_HOST — Value: your PlanetScale database host (e.g., aws.connect.psdb.cloud) - Name: MYSQL_USERNAME — Value: your service token username or database username - Name: MYSQL_PASSWORD — Value: your service token or database password - Name: MYSQL_DATABASE — Value: your database name For a REST proxy (Option B), add: - Name: MYSQL_API_URL — Value: your proxy base URL (e.g., https://mysql-proxy.yourapp.railway.app) - Name: MYSQL_API_KEY — Value: your proxy API key After adding each secret, it appears in the list with its value masked. Do not add your full MySQL connection string as a single secret — splitting it into host, username, and password gives you more flexibility to rotate individual credentials without updating every secret.
Pro tip: After adding secrets, verify they appear in the list before proceeding. If you accidentally added a secret with a typo in the name, delete it and re-add with the correct name — secret names must exactly match Deno.env.get() calls in your Edge Functions.
Expected result: MySQL credentials are stored in Cloud → Secrets with masked values. For PlanetScale: MYSQL_HOST, MYSQL_USERNAME, MYSQL_PASSWORD, and MYSQL_DATABASE. For proxy: MYSQL_API_URL and MYSQL_API_KEY.
Create a read Edge Function using the PlanetScale serverless driver
Create a read Edge Function using the PlanetScale serverless driver
For PlanetScale-hosted MySQL, the Edge Function uses the @planetscale/database package imported directly from esm.sh. This package handles all HTTP communication with PlanetScale's serverless API, executes parameterized queries, and returns results in a familiar format. The import syntax works in Deno without any package.json configuration — Deno's module resolution fetches the package directly from the CDN URL at runtime. The Edge Function below implements a flexible query handler that accepts a named SQL query and parameter values. Like the SQL Server and MongoDB patterns, it uses an allowlist of named queries rather than accepting raw SQL strings from the frontend — this is a critical security pattern that prevents SQL injection even if a malicious actor crafts a specially formed frontend request. For non-PlanetScale MySQL (Option B), the Edge Function body is nearly identical to the SQL Server proxy pattern — replace the PlanetScale client code with a fetch call to your REST proxy using MYSQL_API_URL and MYSQL_API_KEY. Paste the prompt below into Lovable's chat to create the Edge Function, or create the file manually in the Code panel under supabase/functions/.
Create a Supabase Edge Function at supabase/functions/mysql-read/index.ts that queries a PlanetScale MySQL database. Use the @planetscale/database package from esm.sh. Read MYSQL_HOST, MYSQL_USERNAME, MYSQL_PASSWORD, and MYSQL_DATABASE from Deno.env.get. Accept a POST request with 'queryName' and optional 'params' object. Map queryName to pre-defined parameterized SQL queries using an allowlist. Return results as JSON with CORS headers.
Paste this in Lovable chat
1// supabase/functions/mysql-read/index.ts2import { connect } from 'https://esm.sh/@planetscale/database@1';34const corsHeaders = {5 'Access-Control-Allow-Origin': '*',6 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',7};89// Allowlist of named queries — never accept raw SQL from the frontend10const QUERIES: Record<string, { sql: string; paramKeys: string[] }> = {11 get_customers: {12 sql: 'SELECT id, name, email, company, created_at FROM customers ORDER BY created_at DESC LIMIT 50',13 paramKeys: [],14 },15 get_customer_by_id: {16 sql: 'SELECT * FROM customers WHERE id = ?',17 paramKeys: ['id'],18 },19 get_orders: {20 sql: 'SELECT o.id, o.total, o.status, o.created_at, c.name AS customer_name FROM orders o JOIN customers c ON o.customer_id = c.id WHERE o.status = ? ORDER BY o.created_at DESC LIMIT 100',21 paramKeys: ['status'],22 },23 search_products: {24 sql: 'SELECT id, sku, name, price, stock FROM products WHERE name LIKE ? LIMIT 20',25 paramKeys: ['search'],26 },27};2829Deno.serve(async (req) => {30 if (req.method === 'OPTIONS') {31 return new Response('ok', { headers: corsHeaders });32 }3334 try {35 const { queryName, params = {} } = await req.json();36 const queryDef = QUERIES[queryName];3738 if (!queryDef) {39 return new Response(JSON.stringify({ error: `Unknown query: ${queryName}` }), {40 status: 400,41 headers: { ...corsHeaders, 'Content-Type': 'application/json' },42 });43 }4445 const conn = connect({46 host: Deno.env.get('MYSQL_HOST')!,47 username: Deno.env.get('MYSQL_USERNAME')!,48 password: Deno.env.get('MYSQL_PASSWORD')!,49 });5051 const database = Deno.env.get('MYSQL_DATABASE')!;52 const paramValues = queryDef.paramKeys.map((key) => params[key] ?? null);5354 // Add wildcard for LIKE queries55 const processedParams = paramValues.map((v, i) => {56 const sql = queryDef.sql;57 return sql.includes('LIKE') && queryDef.paramKeys[i] === 'search' ? `%${v}%` : v;58 });5960 const results = await conn.execute(61 `USE ${database}; ${queryDef.sql}`,62 processedParams63 );6465 return new Response(JSON.stringify({ rows: results.rows }), {66 headers: { ...corsHeaders, 'Content-Type': 'application/json' },67 });68 } catch (error) {69 console.error('MySQL query error:', error);70 return new Response(JSON.stringify({ error: 'Query failed', details: String(error) }), {71 status: 500,72 headers: { ...corsHeaders, 'Content-Type': 'application/json' },73 });74 }75});Pro tip: The PlanetScale driver creates a new connection per request — this is by design for serverless environments and is safe because PlanetScale handles connection pooling on their infrastructure.
Expected result: The mysql-read Edge Function is deployed. Test calls with valid queryName values return MySQL rows as JSON. Requests with unrecognized query names return a 400 error.
Create a write Edge Function with Supabase auth verification
Create a write Edge Function with Supabase auth verification
For operations that modify MySQL data — INSERT, UPDATE, DELETE — create a separate Edge Function that verifies the user's Supabase JWT before executing any write. This ensures only authenticated users from your Lovable app can mutate your MySQL database, even if someone discovers the Edge Function URL. The write function mirrors the read function's structure but adds auth verification first. It uses Supabase's client library to validate the JWT from the Authorization header and then calls the PlanetScale connection for the write operation. For the write Edge Function, define your write operations in a similar allowlist pattern. Map named operation identifiers to parameterized SQL statements. Never accept raw INSERT or UPDATE SQL from the frontend. If the user's role needs to be checked (for example, only admins can delete records), add a role check after the JWT verification by querying your Supabase database for the user's role. For complex multi-table write operations that need transaction support, consider using MySQL stored procedures callable by name — the REST proxy pattern (Option B) is better suited for transaction-heavy writes than the PlanetScale serverless driver, which does not support interactive transactions in its HTTP API.
Create a Supabase Edge Function at supabase/functions/mysql-write/index.ts that handles MySQL write operations using PlanetScale. Verify the Supabase JWT from the Authorization header before any write. Use MYSQL_HOST, MYSQL_USERNAME, MYSQL_PASSWORD, and MYSQL_DATABASE from Deno env. Accept 'operation' (insert_customer, update_order_status, delete_draft) and 'data' in the request body. Use an allowlist for operations. Return success with affected rows or an error.
Paste this in Lovable chat
1// supabase/functions/mysql-write/index.ts2import { connect } from 'https://esm.sh/@planetscale/database@1';3import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';45const corsHeaders = {6 'Access-Control-Allow-Origin': '*',7 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',8};910const WRITE_OPERATIONS: Record<string, { sql: string; paramKeys: string[] }> = {11 insert_customer: {12 sql: 'INSERT INTO customers (name, email, company, created_at) VALUES (?, ?, ?, NOW())',13 paramKeys: ['name', 'email', 'company'],14 },15 update_order_status: {16 sql: 'UPDATE orders SET status = ?, updated_at = NOW() WHERE id = ?',17 paramKeys: ['status', 'id'],18 },19};2021Deno.serve(async (req) => {22 if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders });2324 const authHeader = req.headers.get('Authorization');25 if (!authHeader) {26 return new Response(JSON.stringify({ error: 'Authentication required' }), {27 status: 401,28 headers: { ...corsHeaders, 'Content-Type': 'application/json' },29 });30 }3132 const supabase = createClient(33 Deno.env.get('SUPABASE_URL')!,34 Deno.env.get('SUPABASE_ANON_KEY')!,35 { global: { headers: { Authorization: authHeader } } }36 );3738 const { data: { user }, error: authError } = await supabase.auth.getUser();39 if (authError || !user) {40 return new Response(JSON.stringify({ error: 'Unauthorized' }), {41 status: 401,42 headers: { ...corsHeaders, 'Content-Type': 'application/json' },43 });44 }4546 try {47 const { operation, data = {} } = await req.json();48 const opDef = WRITE_OPERATIONS[operation];49 if (!opDef) {50 return new Response(JSON.stringify({ error: `Unknown operation: ${operation}` }), {51 status: 400,52 headers: { ...corsHeaders, 'Content-Type': 'application/json' },53 });54 }5556 const conn = connect({57 host: Deno.env.get('MYSQL_HOST')!,58 username: Deno.env.get('MYSQL_USERNAME')!,59 password: Deno.env.get('MYSQL_PASSWORD')!,60 });6162 const database = Deno.env.get('MYSQL_DATABASE')!;63 const paramValues = opDef.paramKeys.map((k) => data[k] ?? null);6465 const result = await conn.execute(66 `USE ${database}; ${opDef.sql}`,67 paramValues68 );6970 return new Response(JSON.stringify({ affectedRows: result.rowsAffected, insertId: result.insertId }), {71 headers: { ...corsHeaders, 'Content-Type': 'application/json' },72 });73 } catch (error) {74 console.error('MySQL write error:', error);75 return new Response(JSON.stringify({ error: String(error) }), {76 status: 500,77 headers: { ...corsHeaders, 'Content-Type': 'application/json' },78 });79 }80});Pro tip: The PlanetScale HTTP driver returns rowsAffected and insertId directly — use insertId to retrieve the newly created record's ID for confirmation messages in your Lovable frontend.
Expected result: The mysql-write Edge Function is deployed. Unauthenticated requests return 401. Authenticated requests with valid operations execute against MySQL and return affected row counts.
Build Lovable frontend components and plan your migration path
Build Lovable frontend components and plan your migration path
With the Edge Functions deployed, build your Lovable frontend components that display and interact with MySQL data. Open the Lovable chat and describe the data you need displayed — Lovable will generate React components that call your Edge Functions using supabase.functions.invoke(). For the migration path consideration: if you plan to eventually move from MySQL to Supabase PostgreSQL — which is recommended for maximizing Lovable's AI-assisted development capabilities — design your Edge Functions as a compatibility layer rather than a permanent architecture. Use the same data shape and naming conventions in your MySQL Edge Functions that you intend to use in Supabase later. When you migrate a table to Supabase, you replace the Edge Function calls with direct Supabase queries in your components — the rest of the UI remains unchanged. To track which tables are still on MySQL versus Supabase, ask Lovable to create a simple admin indicator: 'Add a small database badge to the customer list page showing whether the data is coming from MySQL or Supabase so I can track my migration progress.' This is a simple state variable in the component but keeps you aware of the architecture during the transition period. For complex MySQL-to-Supabase migration strategies including data mapping, RLS policy generation for migrated tables, and zero-downtime cutover planning, RapidDev's team specializes in this transition architecture and can help structure the migration in phases.
Build a customer management page that calls the mysql-read Edge Function with queryName 'get_customers' to show a list. Each row should have an 'Edit' button that opens a modal form. On form submit, call the mysql-write Edge Function with operation 'update_order_status'. Add a 'New Customer' button that calls mysql-write with operation 'insert_customer'. Show loading states and handle errors with toast notifications.
Paste this in Lovable chat
Pro tip: When building components on top of MySQL data, document which Edge Functions each component uses in a comment at the top of the file — this makes the MySQL-to-Supabase migration easier to track as you progress.
Expected result: The customer management page displays real MySQL data from your database. Create and update operations work correctly and reflect in MySQL. The migration plan is documented with a clear list of which tables remain on MySQL versus which are candidates for Supabase migration.
Common use cases
Build a modern admin dashboard on top of a legacy MySQL application
Many businesses run a legacy PHP or Ruby on Rails application backed by MySQL and need a more modern admin interface without rebuilding the entire application. Lovable can serve as the new admin UI layer, reading from and writing to the existing MySQL tables through Edge Functions while the legacy application continues operating normally.
Create Edge Functions to read from my MySQL database's 'orders' and 'customers' tables. Build an admin dashboard page that shows total orders today, revenue this week, and a recent orders table with customer name, order total, and status. Allow admins to update order status by clicking a dropdown in the table.
Copy this prompt to try it in Lovable
Display WordPress MySQL data in a custom Lovable app
WordPress stores posts, pages, users, and custom post type data in MySQL. A Lovable app can query the WordPress MySQL database to display content in a completely custom design, or to build application features on top of WordPress content without modifying WordPress itself — useful when you need WordPress for content management but want a custom app experience for users.
Connect to my WordPress MySQL database and create an Edge Function that queries the wp_posts table for published posts with their titles, slugs, and custom field data from wp_postmeta. Build a custom blog listing page in Lovable that displays these posts in a magazine-style grid layout entirely different from the WordPress theme.
Copy this prompt to try it in Lovable
Migrate gradually from MySQL to Supabase PostgreSQL
The MySQL Edge Function integration serves as a transitional architecture. New features can be built directly on Supabase while legacy data access continues through MySQL Edge Functions. Over time, as tables are migrated to Supabase PostgreSQL, the Edge Functions are replaced by direct Supabase queries and the AI-assisted features become available for those data models.
I'm migrating from MySQL to Supabase. The 'products' table is already migrated to Supabase, but 'orders' and 'customers' are still in MySQL. Create an Edge Function for MySQL order data and use native Supabase queries for products. Build an order detail page that fetches the order from MySQL via Edge Function and enriches it with product details from Supabase.
Copy this prompt to try it in Lovable
Troubleshooting
PlanetScale connection throws 'Error: fetch failed' or 'TypeError: Failed to fetch' in Edge Function logs
Cause: Either the MYSQL_HOST, MYSQL_USERNAME, or MYSQL_PASSWORD secret values are incorrect, the PlanetScale database is paused (free databases pause after 7 days of inactivity), or the database name does not exist.
Solution: Check Cloud → Logs for the full error message. Go to your PlanetScale dashboard at app.planetscale.com and confirm the database is awake (click 'Wake up' if paused). Verify the connection details by navigating to your database → Connect → Connect with HTTP API and confirming the host, username, and password match your secrets exactly. If you recently rotated credentials, update the secrets in Cloud → Secrets.
Edge Function returns data but rows are empty or contain unexpected column names
Cause: The SQL query in the QUERIES allowlist uses column aliases or table prefixes that do not match what you expect, the database name in MYSQL_DATABASE is incorrect, or the table does not exist in the specified database.
Solution: In PlanetScale's dashboard, use the Query Console to run the exact SQL query from your Edge Function directly against your database. This confirms the query syntax and the column names in the result set. Update the query in your Edge Function to match. If the database name is wrong, update the MYSQL_DATABASE secret in Cloud → Secrets.
SQL injection attempt — user input in the 'params' object causes unexpected query behavior
Cause: The parameterized query pattern using ? placeholders should prevent SQL injection, but if query values are being string-concatenated instead of passed as parameters to the PlanetScale driver, user-controlled values can manipulate the SQL.
Solution: Verify that every user-supplied value is passed as an element in the paramValues array to conn.execute(), never concatenated into the SQL string itself. Review the Edge Function code and confirm the SQL only uses ? placeholders for variable values, with the actual values supplied separately. The code examples in this guide follow the correct pattern — if you modified the queries, double-check the parameter passing.
Write operations fail with 'foreign key constraint fails' or 'duplicate entry' MySQL errors
Cause: The data being inserted or updated violates a MySQL foreign key relationship or unique index constraint. MySQL's relational constraints are stricter than MongoDB's flexible document model — a customer_id in an orders INSERT must reference an existing customer, and a UNIQUE email field cannot accept a duplicate value.
Solution: Add client-side validation in your Lovable frontend forms for known constraints (email uniqueness, required foreign keys). In the Edge Function error handler, extract the MySQL error code from the error message and return a user-friendly error — for example, if error code 1062 (duplicate entry), return { error: 'A customer with this email already exists' } rather than the raw MySQL error message.
1// In the Edge Function catch block, parse MySQL error codes:2const mysqlError = error as { code?: string; message?: string };3if (mysqlError.message?.includes('Duplicate entry')) {4 return new Response(JSON.stringify({ error: 'A record with this value already exists' }), {5 status: 409,6 headers: { ...corsHeaders, 'Content-Type': 'application/json' },7 });8}Best practices
- Use PlanetScale as your MySQL host if you have flexibility — it is the only MySQL platform with a serverless HTTP driver that works natively in Deno without a REST proxy layer, simplifying the integration significantly.
- Always use parameterized queries with the ? placeholder syntax and pass values as an array to conn.execute() — never string-concatenate user input into SQL, even in Edge Functions where you might feel the input is trusted.
- Define a query allowlist in the Edge Function rather than accepting queryName values from the frontend and building SQL dynamically — the allowlist means a malicious request can trigger at most one of your pre-approved read-only queries.
- Separate read and write Edge Functions so you can apply different authorization requirements — read functions may be safe for unauthenticated users (public product catalogs), while write functions should always require a verified Supabase JWT.
- Design your MySQL Edge Functions with future Supabase migration in mind: keep the response shape identical to what a Supabase query would return so your frontend components need minimal changes when a table is migrated.
- Monitor your PlanetScale usage in the PlanetScale dashboard — the free plan limits rows read and written per month. For high-traffic Lovable apps, factor these limits into your database tier selection before launch.
- Add database query timing logs in your Edge Function (log the time before and after each query) to identify slow queries early, since MySQL query performance issues become critical once a Lovable app reaches significant user traffic.
Alternatives
Choose Microsoft SQL Server if your organization is deeply embedded in the Microsoft technology stack and needs T-SQL stored procedures, Windows Authentication, or SQL Server Agent jobs — MySQL offers broader open-source hosting flexibility.
Choose MongoDB Atlas if your data is document-oriented with variable schemas — MongoDB's flexible document model avoids schema migrations for evolving data structures that would require ALTER TABLE in MySQL.
Choose PostgreSQL via Lovable's native Supabase integration if you can design your schema from scratch — it provides full AI-assisted development, auto-generated RLS policies, and eliminates the Edge Function proxy requirement entirely.
Frequently asked questions
Does the PlanetScale serverless driver work with any MySQL database or only PlanetScale?
The @planetscale/database package specifically communicates with PlanetScale's HTTP API — it does not work with generic MySQL servers like AWS RDS, Google Cloud SQL, or self-hosted MySQL. For non-PlanetScale MySQL, you need either a REST proxy (as described in Step 1, Option B) or you can import your MySQL data into PlanetScale using their import wizard, which then gives you the serverless driver compatibility.
Can I use Lovable with a self-hosted MySQL database on my own server?
Yes, but your self-hosted MySQL must be accessible over the public internet or through a VPN-connected REST proxy. Deploy a small Node.js Express API on a cloud host (Railway, Render, or Fly.io free tiers work well) that uses the mysql2 package to connect to your server. Expose this API with an API key header and call it from your Lovable Edge Functions. The REST proxy approach described in Step 1 (Option B) applies here.
Is PlanetScale still available after their pricing changes in 2024?
PlanetScale removed their free tier in March 2024 and now starts at $39/month for the Scaler plan. However, they continue to offer a Hobby plan for smaller databases. The @planetscale/database serverless driver continues to work with all PlanetScale plans. If cost is a concern, AWS RDS MySQL with a REST proxy or a managed MySQL service like Aiven (which has a free tier) are alternatives — both require the proxy approach rather than the serverless driver.
What is the performance difference between Edge Function MySQL queries and Lovable's native Supabase queries?
Edge Function MySQL queries add roughly 10-50ms of additional latency compared to Lovable's native Supabase queries, because each request goes through the Edge Function network hop and then to MySQL, versus Supabase queries using an internal connection from the Edge Function to the co-located Supabase database. For interactive UI, this difference is imperceptible. For dashboards making many simultaneous queries, consider batching multiple queries into a single Edge Function call to minimize the number of round trips.
Can I run MySQL migrations and schema changes from Lovable?
No. Lovable's AI-assisted schema management only works with Supabase PostgreSQL — it cannot generate or apply MySQL migrations. Schema changes to your MySQL database must be managed through your normal database tools (MySQL Workbench, TablePlus, or PlanetScale's web console for branch-based schema changes). This is one of the significant advantages of migrating to Supabase: Lovable can create and modify tables, add columns, and set up RLS policies through natural language prompts.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation