Skip to main content
Technology & EngineeringDatabase Services195 lines

Fauna

Build with Fauna as a distributed document-relational database. Use this skill

Quick Summary35 lines
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 lines
Paste into your CLAUDE.md or agent config

Fauna 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

Get CLI access →