To secure a Bolt.new + PlanetScale stack, split production and development onto separate database branches, keep DATABASE_URL in environment variables with SSL on, and push production schema changes through deploy requests rather than straight to main. The one that catches people out: MySQL has no row-level security, so every authorization check has to live in your application code. This blueprint covers the MySQL-specific patterns.
TL;DR
PlanetScale is serverless MySQL with branching. After you export from Bolt, put production and development on separate branches, keep DATABASE_URL in environment variables, and turn SSL on everywhere. Then write your authorization checks by hand in your API routes, because PlanetScale has no RLS to fall back on. Production migrations go through deploy requests.
PlanetScale with Bolt.new
PlanetScale is MySQL underneath, with a few things bolted on that change how you secure it:
| Feature | Security Benefit | Configuration Required |
|---|---|---|
| Database branching | Environment isolation | Create dev/prod branches |
| Deploy requests | Safe migrations | Require approval for prod |
| Connection strings | Credential management | Environment variables |
| SSL connections | Data in transit | sslaccept=strict |
Part 1: PlanetScale Branch Security
Set Up Separate Branches
# Production branch
main
├── Production data
├── Protected from direct schema changes
└── Changes via deploy requests only
# Development branch
development
├── Test data only
├── Safe for schema experimentation
└── Bolt development uses this branch
Connection String Management
# Production (.env.production)
DATABASE_URL="mysql://user:pass@aws.connect.psdb.cloud/mydb?sslaccept=strict"
# Development (.env.development)
DATABASE_URL="mysql://user:pass@aws.connect.psdb.cloud/mydb-dev?sslaccept=strict"
# NEVER commit these files
# Add to .gitignore: .env*
PlanetScale passwords are shown once. Put it in your secrets manager the moment you create it. Lose it and there's no recovery, only a new password.
Part 2: PlanetScale Query Security
Check Bolt-Generated Queries
Bolt writes either Prisma calls or raw SQL, and only one of those is safe by default. Check which you got:
// If Bolt generated raw queries, check for this:
const user = await connection.execute(
`SELECT * FROM users WHERE email = '${email}'` // SQL injection!
);
// Correct pattern
const user = await connection.execute(
'SELECT * FROM users WHERE email = ?',
[email] // Parameterized - safe
);
// Or with Prisma (automatically safe)
const user = await prisma.user.findUnique({
where: { email }
});
Part 3: Application Authorization
MySQL has no row-level security. If you came from Supabase expecting the database to enforce ownership, it won't. Every check is yours to write:
This is the gap we find most often in exported Bolt apps: the route checks that you're logged in, never that the row is yours.
// lib/auth.ts
export async function requireOwnership(
userId: string,
resourceId: string,
resourceType: 'post' | 'comment'
) {
const resource = await prisma[resourceType].findUnique({
where: { id: resourceId }
});
if (!resource) {
throw new NotFoundError(`${resourceType} not found`);
}
if (resource.userId !== userId) {
throw new ForbiddenError('Not authorized');
}
return resource;
}
// Usage in API route
export async function PUT(req: Request, { params }) {
const session = await getSession(req);
if (!session?.user?.id) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
await requireOwnership(session.user.id, params.id, 'post');
// Safe to update...
}
Part 4: Deploy Requests
Safe Migration Workflow
# 1. Make schema changes on development branch
npx prisma db push # Against development DATABASE_URL
# 2. Test your changes
# 3. Create deploy request in PlanetScale dashboard
# Source: development
# Target: main
# 4. Review schema diff
# 5. Deploy when ready (production updated safely)
Security Checklist
Post-Export Checklist for Bolt + PlanetScale
Separate branches for dev and production
DATABASE_URL in environment variables
SSL enabled (sslaccept=strict)
No hardcoded credentials in code
Parameterized queries (no string interpolation)
Authorization checks in API routes
Production changes via deploy requests
.env files in .gitignore
Alternative Stacks to Consider
**Bolt.new + Supabase**
PostgreSQL with built-in RLS
**Bolt.new + MongoDB**
Document database alternative
**Bolt.new + Convex**
Real-time TypeScript database
Does PlanetScale support row-level security?
No. MySQL has nothing equivalent to Postgres RLS, so authorization has to be enforced in your application code. Put the ownership check in shared middleware rather than repeating it per route, and the coverage gaps get much easier to spot.
Why use deploy requests?
They show you the exact schema diff before anything touches production. That's your last chance to catch a dropped column or a renamed table before it takes the data with it.
Can Bolt-generated code use PlanetScale directly?
Yes. PlanetScale is MySQL-compatible, so Bolt's MySQL or Prisma output usually runs once you point the connection string at it. Add ?sslaccept=strict while you're there, since Bolt won't.
Exported a Bolt + PlanetScale app?
Scan for query security and authorization issues.