Fauna
Build with Fauna as a distributed document-relational database. Use this skill
You are a database specialist who integrates Fauna into projects. Fauna is a
distributed, document-relational database with native ACID transactions, global
replication, and a serverless API. It combines the flexibility of documents with
the power of relational queries.
## Key Points
- Define schemas with types — get compile-time safety and runtime validation
- Use indexes for every query pattern — Fauna requires indexed access
- Use FQL's built-in projections to select only needed fields
- Leverage the document-relational model — references are native, not strings
- Use streaming for real-time updates
- All operations are transactional — compose multiple operations in one query
- Fetching documents by ID in a loop — use indexes and set operations
- Not defining indexes for access patterns — queries fail without them
- Creating too many indexes — each index has storage and write cost
- Using the admin key in client-side code — use scoped keys with ABAC
- Ignoring pagination — large result sets need cursor-based pagination
- Not using projections — fetching full documents when you need two fields
## Quick Example
```bash
npm install fauna
```
```typescript
import { Client, fql } from 'fauna';
const client = new Client({
secret: process.env.FAUNA_SECRET!,
});
```skilldb get database-services-skills/FaunaFull skill: 195 linesFauna Integration
You are a database specialist who integrates Fauna into projects. Fauna is a distributed, document-relational database with native ACID transactions, global replication, and a serverless API. It combines the flexibility of documents with the power of relational queries.
Core Philosophy
Document-relational
Fauna stores data as documents but supports relational features — typed schemas, foreign keys, joins, and constraints. You get document flexibility with relational guarantees.
Globally distributed ACID
Every transaction in Fauna is ACID-compliant across all regions. There's no eventual consistency trade-off — strong consistency is the default, everywhere.
Serverless native
Fauna is accessed via HTTPS — no connection pools, no connection strings, no drivers managing TCP sockets. It works in serverless functions, edge runtimes, and browsers.
Setup
Install
npm install fauna
Initialize (v10)
import { Client, fql } from 'fauna';
const client = new Client({
secret: process.env.FAUNA_SECRET!,
});
Key Techniques
Schema definition
// Define collections with typed schemas
collection User {
name: String
email: String
plan: String = "free"
unique [.email]
index byEmail {
terms [.email]
}
}
collection Post {
title: String
content: String
status: String = "draft"
author: Ref<User>
tags: Array<String>
index byAuthor {
terms [.author]
values [desc(.ts)]
}
index byStatus {
terms [.status]
values [desc(.ts)]
}
}
CRUD operations
import { Client, fql } from 'fauna';
const client = new Client({ secret: process.env.FAUNA_SECRET! });
// Create
const user = await client.query(fql`
User.create({
name: "Alice",
email: "alice@example.com",
plan: "free"
})
`);
// Read by ID
const post = await client.query(fql`
Post.byId(${postId})
`);
// Read with index
const posts = await client.query(fql`
Post.byStatus("published").take(20)
`);
// Read with relation
const userPosts = await client.query(fql`
let user = User.byId(${userId})
Post.byAuthor(user).take(20) {
id,
title,
status,
author {
name,
email
}
}
`);
// Update
await client.query(fql`
Post.byId(${postId})!.update({
title: "Updated Title",
status: "published"
})
`);
// Delete
await client.query(fql`
Post.byId(${postId})!.delete()
`);
Transactions
// All FQL queries are transactional by default
const result = await client.query(fql`
let post = Post.byId(${postId})!.update({ status: "published" })
Notification.create({
userId: post.author.id,
type: "post_published",
entityId: post.id
})
post
`);
Pagination
const page = await client.query(fql`
Post.byStatus("published").take(20)
`);
// Next page
if (page.data.after) {
const nextPage = await client.query(fql`
Set.paginate(${page.data.after})
`);
}
Authentication and ABAC
// Create a key with a specific role
const key = await client.query(fql`
Key.create({
role: "user",
data: { userId: ${userId} }
})
`);
// Use the scoped key for user-specific access
const userClient = new Client({ secret: key.data.secret });
Best Practices
- Define schemas with types — get compile-time safety and runtime validation
- Use indexes for every query pattern — Fauna requires indexed access
- Use FQL's built-in projections to select only needed fields
- Leverage the document-relational model — references are native, not strings
- Use streaming for real-time updates
- All operations are transactional — compose multiple operations in one query
Anti-Patterns
- Fetching documents by ID in a loop — use indexes and set operations
- Not defining indexes for access patterns — queries fail without them
- Creating too many indexes — each index has storage and write cost
- Using the admin key in client-side code — use scoped keys with ABAC
- Ignoring pagination — large result sets need cursor-based pagination
- Not using projections — fetching full documents when you need two fields
Install this skill directly: skilldb add database-services-skills
Related Skills
Cassandra
Build with Apache Cassandra for high-availability distributed data. Use this skill
Clickhouse
Build with ClickHouse for real-time analytics and OLAP workloads. Use this skill
Cockroachdb
Build with CockroachDB as a distributed SQL database. Use this skill when the
Convex
Build with Convex as a reactive backend. Use this skill when the project needs
Drizzle
Use Drizzle ORM for type-safe SQL in TypeScript. Use this skill when the project
Dynamodb
Build with Amazon DynamoDB as a serverless NoSQL database. Use this skill when