Seeding Firebase Firestore and Supabase with Fake JSON Data
Firestore's document/collection model and Supabase's relational Postgres model need different seeding approaches — Firestore has no bulk-insert SQL to fall back on, while Supabase is a full Postgres database under the hood. Here's the practical way to seed each with realistic fake data, without clicking through a console one record at a time.
Step 1: Generate the Dataset First
Regardless of which backend you're seeding, start by shaping your data with Dummy JSON Generator — export as JSON for Firestore, or as SQL for a direct Supabase/Postgres insert.
[
{ "id": "p1", "name": "Wireless Mouse", "price": 24.99, "inStock": true },
{ "id": "p2", "name": "USB-C Hub", "price": 34.99, "inStock": false }
]Seeding Firestore with the Admin SDK
Firestore has no native "import a JSON array" command in the console for nested collections, so the standard approach is a small Node script using the Admin SDK, writing each record as a document via a batched write (faster and cheaper than individual .set() calls for bulk data).
import admin from 'firebase-admin'
import products from './mock/products.json' assert { type: 'json' }
admin.initializeApp({ credential: admin.credential.applicationDefault() })
const db = admin.firestore()
async function seed() {
const batch = db.batch()
for (const product of products) {
const ref = db.collection('products').doc(product.id)
batch.set(ref, product)
}
await batch.commit()
console.log(`Seeded ${products.length} products`)
}
seed()Note: Firestore batched writes are capped at 500 operations per batch — for larger datasets, chunk your array and commit multiple batches sequentially.
function chunk<T>(arr: T[], size: number): T[][] {
return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
arr.slice(i * size, i * size + size)
)
}
for (const group of chunk(products, 500)) {
const batch = db.batch()
group.forEach(p => batch.set(db.collection('products').doc(p.id), p))
await batch.commit()
}Seeding Supabase — Two Ways
Option A: Direct SQL insert. Since Supabase is Postgres, export your generated dataset directly as INSERT statements and run them through the SQL Editor or `psql`.
INSERT INTO products (id, name, price, in_stock) VALUES
('p1', 'Wireless Mouse', 24.99, true),
('p2', 'USB-C Hub', 34.99, false);Option B: Supabase JS client. If you want the seed script to run as part of your app's tooling rather than a raw SQL file, use the same client library your app already depends on.
import { createClient } from '@supabase/supabase-js'
import products from './mock/products.json' assert { type: 'json' }
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!)
const { error } = await supabase.from('products').insert(products)
if (error) console.error(error)
else console.log(`Seeded ${products.length} products`)Important: use the service role key for seed scripts, not the public anon key — Row Level Security policies will otherwise silently block inserts that don't match an authenticated user context.
Handling Relationships
Supabase's relational model means foreign keys need to be seeded in dependency order — insert `users` before `orders` that reference a `user_id`. Firestore's document model sidesteps this since documents reference each other by ID string rather than an enforced foreign key, but you're responsible for ensuring referenced IDs actually exist, since Firestore won't reject a document pointing at a non-existent one.
Cleaning Up Between Test Runs
For repeatable test seeding, wipe the collection or table before re-seeding rather than accumulating duplicate records across runs.
-- Supabase / Postgres
TRUNCATE TABLE products RESTART IDENTITY CASCADE;Firestore has no native "truncate collection" operation — you have to fetch and batch-delete existing documents in the same way you batch-wrote them.
The Bottom Line
Firestore seeding means batched document writes through the Admin SDK, chunked at 500 operations per batch. Supabase seeding means either a direct SQL insert or the JS client with the service role key, respecting foreign key order. Generate the dataset once, and both paths are a short script away from a fully populated dev environment.