Local development for Lovable apps without Docker
Lovable is great for the cloud-hosted development loop. The friction shows up when you want a copy running on your laptop, pointed at a local database, so you can iterate offline or test schema changes safely. The usual answer is Docker, and Docker is fine, but it is also slow to start, heavy on memory, and another thing to debug when something goes wrong.
SpinDB is the alternative: it runs the actual database binaries (Postgres, Valkey, Qdrant, the rest) directly on your machine, one command per engine. No Docker, no container layer, no networking weirdness. This post is how to use it to mirror a Lovable app locally.
Contents
- Install SpinDB
- Mirror your Lovable database
- Point the app at the local database
- Sync data from production
- Why no Docker
Install SpinDB
SpinDB is on npm. One command:
npm i -g spindbThat installs spindb. The first time you create a database it downloads the engine binary (about 80MB for Postgres) and caches it. Subsequent creates of the same engine reuse the binary.
Mirror your Lovable database
In your Lovable project, you have one or more databases. For most apps that is just Postgres. Create a matching local one:
spindb create lovable-dev --engine postgresql --startThis boots a Postgres on a local port (5433 or the next free one). spindb url lovable-dev prints the connection string:
postgresql://localhost:5433/lovable_devIf your Lovable app also uses Valkey for caching or Qdrant for vector search, add them:
spindb create lovable-dev-cache --engine valkey --start
spindb create lovable-dev-rag --engine qdrant --startThree commands, three databases, total time under thirty seconds.
Point the app at the local database
In your Lovable repository (you can clone Lovable projects to a local git repo), create a .env.local that overrides the production URLs:
DATABASE_URL=postgresql://localhost:5433/lovable_dev
REDIS_URL=redis://localhost:6379
QDRANT_URL=http://localhost:6333
QDRANT_API_KEY=Local Qdrant does not require an API key, so leave it empty. Local Valkey listens on the default Redis port without TLS, so use redis:// (one s).
Run your app's local dev command (usually pnpm dev or npm run dev) and the same code that talks to Layerbase Cloud in production now talks to your local SpinDB instances. The connection string is the only thing that changes.
Schema and migrations
If you use Drizzle, run drizzle-kit push against the local URL to apply your schema:
DATABASE_URL=postgresql://localhost:5433/lovable_dev pnpm drizzle-kit pushIf you use plain SQL migrations:
psql postgresql://localhost:5433/lovable_dev -f migrations/001_init.sqlThe local database is empty until you do this, so the first step in any local dev session is "apply migrations." Add it as a script in package.json:
{
"scripts": {
"db:setup": "drizzle-kit push --config drizzle.config.dev.ts"
}
}Sync data from production
A common workflow is "pull a recent copy of production data into local so I can reproduce a bug." For a small Postgres this is two commands.
Dump from production:
pg_dump \
--no-owner --no-acl --data-only \
"$PROD_DATABASE_URL" \
> prod-data.sqlLoad into local:
psql postgresql://localhost:5433/lovable_dev < prod-data.sqlBe careful with PII. If your production has real user data, scrub it before loading locally. The shape that works for most apps:
update users set
email = 'user-' || id || '@example.com',
full_name = 'User ' || id;Run that against the local copy after the load, before you start debugging. Now you have realistic-looking data without the legal liability of carrying real emails around on your laptop.
Why no Docker
Docker works. The issue is the overhead, not the correctness.
A Docker-based Postgres takes 5 to 10 seconds to start cold. SpinDB takes 1 to 2. On a workflow where you create and destroy local databases several times a day (test isolation, branch-specific schemas), that adds up.
Docker on macOS runs in a Linux VM, which means file I/O between the host and the container goes through a translation layer that is slower than direct file I/O on the same machine. For a small database the difference is invisible. For a 5GB Postgres it is noticeable.
Docker uses 1 to 2 GB of memory per container even when idle, because the daemon and the VM are always running. SpinDB uses memory only when an engine is actually running, and stops it when you say so.
Docker is also another tool to debug when things go wrong. Networking, volumes, port mapping, image versions. SpinDB is "did the process start, yes or no." The failure modes are simpler.
None of this matters if you already have Docker installed and working. If you do not, SpinDB is a smaller download and a simpler workflow. What is SpinDB? has the rest.
Useful SpinDB commands
The five I use most:
spindb list # all databases, running or stopped
spindb url lovable-dev # print the connection string
spindb stop lovable-dev # stop without deleting data
spindb start lovable-dev # restart, same data, same port
spindb destroy lovable-dev # remove permanentlyFor a longer workflow including multi-engine and connecting from external tools, see Managing multiple databases locally.
Wrapping up
The short version of "develop a Lovable app locally":
npm i -g spindbspindb create lovable-dev --engine postgresql --start- Put
DATABASE_URL=postgresql://localhost:5433/lovable_devin.env.local - Run your app, develop against the local database
- Push your changes back into Lovable when they work
The point of mirroring locally is not to replace Lovable. It is to give yourself a fast iteration loop for the parts that touch the database. Schema changes, query tuning, bug reproduction, all of those go faster when the database is on the same machine as your editor. Once it works locally, deploy with confidence.