To secure a Bolt.new + Supabase stack, you need to: (1) verify RLS is enabled on all tables after exporting from Bolt, (2) ensure only the anon key is used in client code while the service_role key stays server-side, (3) review authentication flows for proper session handling, and (4) add explicit user ID checks to data queries. This blueprint covers post-export security tasks with color-coded guidance for each platform.
TL;DR
Bolt.new generates full-stack apps rapidly, but often skips Supabase security configuration. Critical issues: RLS is frequently disabled or misconfigured, service_role keys may be exposed in client code, and authentication flows often lack proper session handling. After exporting from Bolt, immediately configure RLS policies, verify key usage, and add auth checks to any server-side code.
Bolt.new Security Considerations
Bolt.new generates working apps quickly, but security requires post-generation review:
| What Bolt Does Well | What Needs Review |
|---|---|
| Generates working Supabase client setup | RLS policies may be missing or permissive |
| Creates authentication UI | Session handling may be incomplete |
| Scaffolds CRUD operations | Authorization checks often missing |
| Sets up environment variables | May expose service_role key |
Part 1: Check Supabase RLS Configuration
Verify RLS is Enabled
After exporting your Bolt project, check Supabase dashboard:
-- Run in Supabase SQL Editor
SELECT
schemaname,
tablename,
rowsecurity
FROM pg_tables
WHERE schemaname = 'public';
-- If rowsecurity is 'false', enable it:
ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;
Add Proper RLS Policies
-- User profiles: only owner can access
CREATE POLICY "Users can view own profile"
ON profiles FOR SELECT
USING (auth.uid() = id);
CREATE POLICY "Users can update own profile"
ON profiles FOR UPDATE
USING (auth.uid() = id);
-- User's items: full access to own data
CREATE POLICY "Users can manage own items"
ON items FOR ALL
USING (auth.uid() = user_id);
-- Public read, authenticated write
CREATE POLICY "Anyone can read posts"
ON posts FOR SELECT
USING (true);
CREATE POLICY "Authenticated users can create posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = author_id);
Bolt often generates: allow read, write: if true equivalent policies or skips RLS entirely. Always verify before deploying.
Part 2: Supabase API Key Security
Check Key Usage in Generated Code
Search your exported code for key usage:
# In your exported project directory
grep -r "service_role" .
grep -r "supabase" . --include="*.ts" --include="*.js"
# Look for hardcoded keys
grep -r "eyJ" . --include="*.ts" --include="*.js"
Correct Key Setup
import { createClient } from '@supabase/supabase-js'
// Only use anon key in client code
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
// NEVER do this in client code:
// const supabase = createClient(url, process.env.SUPABASE_SERVICE_ROLE_KEY)
Part 3: Authentication Flow
Verify Session Handling
Bolt-generated auth often needs session persistence fixes:
import { useEffect, useState } from 'react'
import { supabase } from '../lib/supabase'
import { User, Session } from '@supabase/supabase-js'
export function useAuth() {
const [user, setUser] = useState<User | null>(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
// Get initial session
supabase.auth.getSession().then(({ data: { session } }) => {
setUser(session?.user ?? null)
setLoading(false)
})
// Listen for auth changes
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_event, session) => {
setUser(session?.user ?? null)
}
)
return () => subscription.unsubscribe()
}, [])
return { user, loading }
}
Part 4: Data Fetching Security
Add Authorization to Queries
Bolt-generated queries may fetch without checking ownership:
// May fetch all items regardless of owner
const { data } = await supabase
.from('items')
.select('*')
// With proper RLS, this returns only user's items
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
throw new Error('Not authenticated')
}
const { data } = await supabase
.from('items')
.select('*')
.eq('user_id', user.id) // Explicit filter (defense in depth)
Security Checklist
Post-Export Checklist for Bolt + Supabase
RLS enabled on all tables
RLS policies restrict access properly
Only anon key used in client code
Service role key not in repository
Auth state properly persisted
Protected routes check authentication
Environment variables not hardcoded
No sensitive data in git history
Alternative Stacks to Consider
**Bolt.new + Firebase**
If you prefer Firebase's ecosystem
**Bolt.new + Supabase + Vercel**
Add Vercel deployment security
**Bolt.new + Convex**
Real-time alternative with built-in functions
Can I trust Bolt-generated Supabase code?
Bolt generates functional code, but security configuration requires manual review. Always check RLS policies, key usage, and authentication flows before deploying to production.
Why does my Bolt app work without RLS?
Without RLS, the anon key grants read/write access to all data. This is convenient for development but dangerous in production. Enable and configure RLS before going live.
How do I add server-side code to a Bolt app?
Export your Bolt project and add API routes or server functions to your deployment platform. Use the service_role key only in server-side code for admin operations.