Date: 2025-01-27
Impact: Development only (production unchanged)
Risk: Low (old data preserved, migration script provided)
/workspaces/tada/app/data/db.sqlite ← Development database (INSIDE watched directory)
/workspaces/tada/data/db.sqlite ← Development database (OUTSIDE watched directory)
Problem: File watcher (chokidar) monitors app/ directory for hot reload. When SQLite creates/deletes journal files during transactions, the watcher tries to watch them, causing EINVAL errors and server crashes.
Solution: Move database outside the watched directory in development. The watcher never sees journal files, no more conflicts.
✅ Production is unaffected:
- Production uses
DATABASE_URLenvironment variable (set in CapRover) - CapRover persistent volume:
/var/lib/caprover/appsdata/tadata→/data - Container database path:
/data/db.sqlite(unchanged) - See DEPLOY_CAPROVER.md for production config
Run the migration script from the repository root:
cd /workspaces/tada
./scripts/migrate-db-location.shWhat it does:
- Checks both locations for existing databases
- Compares file sizes to find which has more data
- Backs up the target location before overwriting
- Copies database + journal files to new location
- Preserves old location for safety
If you prefer to do it manually:
# From repository root
mkdir -p data
cp app/data/db.sqlite data/db.sqlite
# Copy journal files if they exist
cp app/data/db.sqlite-wal data/db.sqlite-wal 2>/dev/null || true
cp app/data/db.sqlite-shm data/db.sqlite-shm 2>/dev/null || trueAfter migration, verify the new location works:
# Check file exists and has data
ls -lh data/db.sqlite
# Start dev server
cd app
bun run dev
# Create an entry - watch for EINVAL errors (should be gone!)If you need to rollback to the old location:
- Stop the dev server
- Set environment variable:
export DATABASE_URL="file:./data/db.sqlite" - Copy data back:
cp data/db.sqlite app/data/db.sqlite - Restart dev server
| Environment | Location | Path Type | Watcher Conflict? |
|---|---|---|---|
| Development | /workspaces/tada/data/db.sqlite |
Absolute | ❌ No (outside app/) |
| Production | /data/db.sqlite (in container) |
From DATABASE_URL |
N/A (no watcher) |
| Old Dev | /workspaces/tada/app/data/db.sqlite |
Relative | ✅ Yes (was causing issues) |
Both locations are ignored:
# Root .gitignore
data/
*.sqlite
*.sqlite-wal
*.sqlite-shmAll tools use DATABASE_URL env var with consistent fallback:
| Context | How DATABASE_URL is set | Resolves to |
|---|---|---|
bun run dev |
package.json: DATABASE_URL=file:../data/db.sqlite |
/workspaces/tada/data/db.sqlite |
bun run db:migrate |
package.json: DATABASE_URL=file:../data/db.sqlite |
/workspaces/tada/data/db.sqlite |
bun run db:studio |
package.json: DATABASE_URL=file:../data/db.sqlite |
/workspaces/tada/data/db.sqlite |
| Production (CapRover) | Container env var: DATABASE_URL=file:/data/db.sqlite |
/data/db.sqlite |
| Docker Compose | docker-compose.yml sets it | /app/data/db.sqlite |
{
"dev": "DATABASE_URL=file:../data/db.sqlite nuxt dev",
"db:migrate": "DATABASE_URL=file:../data/db.sqlite drizzle-kit migrate",
"db:studio": "DATABASE_URL=file:../data/db.sqlite drizzle-kit studio"
}// Fallback only - package.json scripts should always set DATABASE_URL
const databaseUrl = process.env["DATABASE_URL"] || "file:../data/db.sqlite";const databaseUrl = process.env["DATABASE_URL"] || 'file:../data/db.sqlite';Key points:
DATABASE_URLis set by package.json scripts (dev) or container env vars (prod)- Do NOT set DATABASE_URL in
.env- it causes conflicts with package.json - All fallbacks use
../data/db.sqlite(relative to app/, outside watched directory) - Production always uses explicit env var from container/CapRover
After confirming the new location works for a few days, you can safely delete the old location:
# Remove old database (from repository root)
rm -rf app/data/db.sqlite*
# Keep the directory for logs/test files
# app/data/logs/ is still usedCheck your current directory and the database path:
pwd # Should be /workspaces/tada/app
ls -la ../data/db.sqlite # Should exist- Verify database is at
/workspaces/tada/data/db.sqlite(notapp/data/) - Restart the dev server completely
- Check
ps aux | grep nodefor zombie processes
- Check DATABASE_URL is set in CapRover:
file:/data/db.sqlite - Verify persistent volume is mounted:
/var/lib/caprover/appsdata/tadata→/data - Database files should be in the persistent volume on the host machine
scripts/migrate-db-location.sh- Migration scriptserver/db/index.ts- Database initialization with new path logicdocs/DEPLOY_CAPROVER.md- Production deployment configuration.gitignore- Ensures database files are never committed
-
Q: Will this affect my existing data?
A: No, the migration script copies your data safely. Old location is preserved. -
Q: What about production?
A: Production usesDATABASE_URLenv var, completely unaffected by this change. -
Q: Can I still use a custom DATABASE_URL?
A: Yes,DATABASE_URLalways takes precedence over defaults. -
Q: What if I'm on Windows?
A: The path logic works cross-platform.../data/resolves correctly on Windows too.