Skip to content

Production Databases

Slingshot’s adapter model means your business logic never knows which database it’s running against. Every package — auth, community, your own entities — takes a store type. Swap it in one place.

In development, you use 'memory' for everything. It’s fast, zero-setup, and resets on restart. For production, you change the adapter name. Nothing else changes.

// Development
db: { auth: 'memory', sessions: 'memory' }
// Production
db: { auth: 'postgres', sessions: 'redis' }

SQLite requires no extra dependencies. It’s built into Bun and is a great starting point for small deployments.

app.config.ts (excerpt)
export default defineApp({
db: {
sqlite: './data/app.db',
},
plugins: [
createAuthPlugin({
auth: { roles: ['user'], defaultRole: 'user' },
db: { auth: 'sqlite', sessions: 'sqlite', oauthState: 'sqlite' },
}),
],
packages: [createCommunityPackage()],
});
Terminal window
bun add @lastshotlabs/slingshot-postgres
app.config.ts (excerpt)
export default defineApp({
db: {
postgres: process.env.DATABASE_URL,
},
plugins: [
createAuthPlugin({
auth: { roles: ['user'], defaultRole: 'user' },
db: { auth: 'postgres', sessions: 'postgres', oauthState: 'postgres' },
}),
],
packages: [createCommunityPackage()],
});
Terminal window
bun add mongoose
app.config.ts (excerpt)
export default defineApp({
db: {
mongo: process.env.MONGO_URL,
},
plugins: [
createAuthPlugin({
auth: { roles: ['user'], defaultRole: 'user' },
db: { auth: 'mongo', sessions: 'mongo', oauthState: 'mongo' },
}),
],
packages: [createCommunityPackage()],
});

A common production setup: durable records in Postgres or SQLite, high-throughput sessions in Redis.

Terminal window
bun add ioredis
app.config.ts (excerpt)
export default defineApp({
db: {
postgres: process.env.DATABASE_URL,
redis: process.env.REDIS_URL,
},
plugins: [
createAuthPlugin({
auth: { roles: ['user'], defaultRole: 'user' },
db: { auth: 'postgres', sessions: 'redis', oauthState: 'postgres' },
}),
],
});

Different parts of your app can use different stores. Each adapter config is independent:

app.config.ts (excerpt)
export default defineApp({
db: {
sqlite: './data/app.db',
redis: process.env.REDIS_URL!,
},
plugins: [
createAuthPlugin({
db: { auth: 'sqlite', sessions: 'redis', oauthState: 'memory' },
}),
],
packages: [createCommunityPackage()],
});

Slingshot generates database migrations from your entity definitions. Each migrate generate invocation diffs every entity against its last snapshot and writes one timestamped .sql file per backend under migrations/.

Terminal window
# Generate a new migration from current entity diffs
slingshot migrate generate --name init
# Apply pending migrations to the configured DB
slingshot migrate apply
# Show applied vs pending migrations (and detect file drift)
slingshot migrate status
# Inner-loop shortcut: generate + apply in one step
slingshot migrate dev --name add_nickname

The backend is auto-detected from infrastructure.db.postgres, infrastructure.db.sqlite, or infrastructure.db.mongo in app.config.ts. Override with --backend postgres|sqlite|mongo, or pass a connection string with --db-url (Postgres falls back to DATABASE_URL; Mongo to MONGODB_URI / MONGO_URL). Applied migrations are tracked in the _slingshot_entity_migrations table (or collection, for Mongo).