Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/rjdellecese/confect/llms.txt

Use this file to discover all available pages before exploring further.

The @confect/server package provides server-side APIs for implementing queries, mutations, and actions with full type safety and Effect integration.

Overview

Database Operations

Type-safe database reads and writes with schema validation

Context Services

Access to QueryCtx, MutationCtx, and ActionCtx

Function Runners

Execute queries, mutations, and actions programmatically

Effect Integration

Full integration with Effect for composable error handling

DatabaseReader

The DatabaseReader service provides type-safe read access to your database.

Accessing DatabaseReader

packages/server/src/DatabaseReader.ts
import { DatabaseReader } from "@confect/server";
import { Effect } from "effect";
import type { databaseSchema } from "../schema";

type DB = DatabaseReader<typeof databaseSchema>;

const listUsers = Effect.gen(function* () {
  const db = yield* DatabaseReader<typeof databaseSchema>();
  
  const users = yield* db
    .table("users")
    .collect();
  
  return users;
});

Query Operations

table

Access a specific table for querying

collect

Collect all documents matching the query

first

Get the first document matching the query

unique

Get a unique document by index

Examples

// Get all documents
const allUsers = yield* db
  .table("users")
  .collect();

// Filter with where clause
const activeUsers = yield* db
  .table("users")
  .filter((q) => q.eq(q.field("status"), "active"))
  .collect();

// Get first matching document
const firstUser = yield* db
  .table("users")
  .filter((q) => q.eq(q.field("email"), "user@example.com"))
  .first();

// Get by unique index
const userByEmail = yield* db
  .table("users")
  .getByIndex("by_email", "user@example.com");

// Order results
const sortedPosts = yield* db
  .table("posts")
  .order("desc")
  .collect();

// Pagination
const paginatedUsers = yield* db
  .table("users")
  .paginate({ numItems: 20, cursor: null });

Get Document by ID

import type { Id } from "convex/values";

const getUser = (userId: Id<"users">) =>
  Effect.gen(function* () {
    const db = yield* DatabaseReader<typeof databaseSchema>();
    
    const user = yield* db
      .table("users")
      .get(userId);
    
    if (user === null) {
      return yield* Effect.fail(new Error("User not found"));
    }
    
    return user;
  });

DatabaseWriter

The DatabaseWriter service provides type-safe write access to your database.

Accessing DatabaseWriter

packages/server/src/DatabaseWriter.ts
import { DatabaseWriter } from "@confect/server";
import { Effect } from "effect";
import type { databaseSchema } from "../schema";

const createUser = Effect.gen(function* () {
  const db = yield* DatabaseWriter<typeof databaseSchema>();
  
  const userId = yield* db.table("users").insert({
    name: "Alice",
    email: "alice@example.com",
    status: "active"
  });
  
  return userId;
});

Write Operations

insert

Insert a new document and return its ID

patch

Update specific fields of a document

replace

Replace entire document (except system fields)

delete

Delete a document by ID

Examples

import type { Id } from "convex/values";

// Insert a document
const userId = yield* db.table("users").insert({
  name: "Bob",
  email: "bob@example.com",
  role: "user"
});

// Patch (partial update)
yield* db.table("users").patch(userId, {
  status: "verified"
});

// Replace (full update)
yield* db.table("users").replace(userId, {
  name: "Bob Smith",
  email: "bob.smith@example.com",
  role: "admin",
  status: "active"
});

// Delete
yield* db.table("users").delete(userId);

Complex Write Example

const createPostWithTags = (
  title: string,
  content: string,
  tags: string[]
) =>
  Effect.gen(function* () {
    const db = yield* DatabaseWriter<typeof databaseSchema>();
    const auth = yield* Auth();
    
    const identity = yield* auth.getUserIdentity();
    if (!identity) {
      return yield* Effect.fail(new Error("Not authenticated"));
    }
    
    // Create the post
    const postId = yield* db.table("posts").insert({
      title,
      content,
      authorId: identity.subject,
      createdAt: Date.now()
    });
    
    // Create tag associations
    for (const tag of tags) {
      yield* db.table("postTags").insert({
        postId,
        tag
      });
    }
    
    return postId;
  });

Context Services

Confect provides type-safe context services for each function type.

QueryCtx

packages/server/src/QueryCtx.ts
import { QueryCtx } from "@confect/server";
import type { GenericDataModel } from "convex/server";

type DataModel = GenericDataModel;

const useQueryContext = Effect.gen(function* () {
  const ctx = yield* QueryCtx<DataModel>();
  
  // Access query context methods
  const db = ctx.db;
  const auth = ctx.auth;
});

MutationCtx

packages/server/src/MutationCtx.ts
import { MutationCtx } from "@confect/server";
import type { GenericDataModel } from "convex/server";

type DataModel = GenericDataModel;

const useMutationContext = Effect.gen(function* () {
  const ctx = yield* MutationCtx<DataModel>();
  
  // Access mutation context methods
  const db = ctx.db;
  const auth = ctx.auth;
  const storage = ctx.storage;
  const scheduler = ctx.scheduler;
});

ActionCtx

packages/server/src/ActionCtx.ts
import { ActionCtx } from "@confect/server";
import type { GenericDataModel } from "convex/server";

type DataModel = GenericDataModel;

const useActionContext = Effect.gen(function* () {
  const ctx = yield* ActionCtx<DataModel>();
  
  // Access action context methods
  const runQuery = ctx.runQuery;
  const runMutation = ctx.runMutation;
  const auth = ctx.auth;
  const storage = ctx.storage;
  const scheduler = ctx.scheduler;
});

Function Runners

Run functions programmatically from within other functions.

QueryRunner

packages/server/src/QueryRunner.ts
import { QueryRunner } from "@confect/server";
import { refs } from "../confect/_generated/refs";

const composedQuery = Effect.gen(function* () {
  const runQuery = yield* QueryRunner;
  
  // Run another query
  const users = yield* runQuery(
    refs.internal.users.list,
    {}
  );
  
  return users.map(u => u.name);
});

MutationRunner

packages/server/src/MutationRunner.ts
import { MutationRunner } from "@confect/server";
import { refs } from "../confect/_generated/refs";

const composedMutation = Effect.gen(function* () {
  const runMutation = yield* MutationRunner;
  
  // Run another mutation
  const userId = yield* runMutation(
    refs.internal.users.create,
    {
      name: "Charlie",
      email: "charlie@example.com"
    }
  );
  
  return userId;
});

ActionRunner

packages/server/src/ActionRunner.ts
import { ActionRunner } from "@confect/server";
import { refs } from "../confect/_generated/refs";

const composedAction = Effect.gen(function* () {
  const runAction = yield* ActionRunner;
  
  // Run another action
  const result = yield* runAction(
    refs.internal.notifications.send,
    {
      userId: "user123",
      message: "Hello!"
    }
  );
  
  return result;
});

Additional Services

Auth

Authentication service for accessing user identity.
packages/server/src/Auth.ts
import { Auth } from "@confect/server";

const checkAuth = Effect.gen(function* () {
  const auth = yield* Auth();
  
  const identity = yield* auth.getUserIdentity();
  
  if (!identity) {
    return yield* Effect.fail(new Error("Not authenticated"));
  }
  
  return {
    userId: identity.subject,
    email: identity.email,
    name: identity.name
  };
});

Storage

File storage operations.
packages/server/src/Storage.ts
import { Storage } from "@confect/server";

const uploadFile = (content: ArrayBuffer) =>
  Effect.gen(function* () {
    const storage = yield* Storage;
    
    const storageId = yield* Effect.promise(() =>
      storage.store(new Blob([content]))
    );
    
    return storageId;
  });

const getFileUrl = (storageId: Id<"_storage">) =>
  Effect.gen(function* () {
    const storage = yield* Storage;
    
    const url = yield* Effect.promise(() =>
      storage.getUrl(storageId)
    );
    
    return url;
  });

Scheduler

Schedule functions to run later.
packages/server/src/Scheduler.ts
import { Scheduler } from "@confect/server";
import { refs } from "../confect/_generated/refs";

const scheduleTask = Effect.gen(function* () {
  const scheduler = yield* Scheduler;
  
  // Schedule after 1 hour
  yield* Effect.promise(() =>
    scheduler.runAfter(
      3600000, // 1 hour in ms
      refs.internal.tasks.processData,
      { taskId: "task123" }
    )
  );
  
  // Schedule at specific time
  const targetTime = new Date("2026-03-08T12:00:00Z");
  yield* Effect.promise(() =>
    scheduler.runAt(
      targetTime,
      refs.internal.tasks.sendReminder,
      { userId: "user123" }
    )
  );
});

DatabaseSchema

Define your database schema with type safety.

Creating a Schema

packages/server/src/DatabaseSchema.ts
import { DatabaseSchema, Table } from "@confect/server";
import { Schema } from "effect";
import { defineTable } from "convex/server";
import { v } from "convex/values";

const usersTable = Table.make(
  "users",
  defineTable({
    name: v.string(),
    email: v.string(),
    role: v.union(
      v.literal("user"),
      v.literal("admin")
    ),
    status: v.string()
  })
    .index("by_email", ["email"])
    .index("by_role", ["role"]),
  {
    name: Schema.String,
    email: Schema.String,
    role: Schema.Literal("user", "admin"),
    status: Schema.String
  }
);

const postsTable = Table.make(
  "posts",
  defineTable({
    title: v.string(),
    content: v.string(),
    authorId: v.string(),
    createdAt: v.number()
  })
    .index("by_author", ["authorId"])
    .searchIndex("search_title", {
      searchField: "title"
    }),
  {
    title: Schema.String,
    content: Schema.String,
    authorId: Schema.String,
    createdAt: Schema.Number
  }
);

const databaseSchema = DatabaseSchema.make()
  .addTable(usersTable)
  .addTable(postsTable);

export default databaseSchema;

Schema Type Extraction

import type { DatabaseSchema } from "@confect/server";

type Tables = DatabaseSchema.Tables<typeof databaseSchema>;
type TableNames = DatabaseSchema.TableNames<typeof databaseSchema>;

HTTP API

Define HTTP routes for your backend.
packages/server/src/HttpApi.ts
import { HttpApi } from "@confect/server";
import { httpRouter } from "convex/server";

const http = httpRouter();

http.route({
  path: "/api/health",
  method: "GET",
  handler: async () => {
    return new Response(
      JSON.stringify({ status: "ok" }),
      {
        status: 200,
        headers: { "Content-Type": "application/json" }
      }
    );
  }
});

http.route({
  path: "/api/webhook",
  method: "POST",
  handler: async (request) => {
    const data = await request.json();
    // Process webhook
    return new Response(null, { status: 200 });
  }
});

export default http;

Next Steps

Core API

Learn about core types and specifications

React Hooks

Use Confect in your React app

Testing

Test your server functions

CLI

Manage your project with the CLI