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.

Confect projects follow a structured directory layout that separates concerns and makes your codebase easy to navigate. This guide explains the recommended project structure and where different types of files belong.

Directory Overview

A typical Confect project has two main directories:

confect/

Your Confect specifications, implementations, and schemas

convex/

Generated Convex functions and traditional Convex files

confect/ Directory

The confect/ directory contains all your Confect-specific code:
confect/
├── _generated/          # Generated by Confect CLI (do not edit)
│   ├── api.ts
│   ├── refs.ts
│   ├── services.ts
│   └── registeredFunctions.ts
├── spec/                # Function specifications
│   ├── users.ts
│   └── notes/
│       ├── create.ts
│       └── list.ts
├── impl/                # Function implementations
│   ├── users.ts
│   └── notes/
│       ├── create.ts
│       └── list.ts
├── tables/              # Database table definitions
│   ├── Users.ts
│   ├── Notes.ts
│   └── Tags.ts
├── spec.ts              # Root specification
├── impl.ts              # Root implementation
└── schema.ts            # Database schema

_generated/

Never edit files in _generated/ directly. These files are automatically generated by the Confect CLI.
Generated files include:
  • api.ts - Type-safe API object for calling functions
  • refs.ts - Type-safe function references for scheduling and internal calls
  • services.ts - Effect service types (DatabaseReader, DatabaseWriter, etc.)
  • registeredFunctions.ts - Registry of all functions for Convex

spec/

Function specifications define your API contract:
spec/notes/create.ts
import { FunctionSpec, GenericId } from "@confect/core";
import { Schema } from "effect";

export const create = FunctionSpec.publicMutation({
  name: "create",
  args: Schema.Struct({
    text: Schema.String,
  }),
  returns: GenericId.GenericId("notes"),
});
Organize specs into subdirectories that mirror your domain structure.

impl/

Function implementations contain your business logic:
impl/notes/create.ts
import { FunctionImpl } from "@confect/server";
import { Effect } from "effect";
import api from "../../_generated/api";
import { DatabaseWriter } from "../../_generated/services";

export const create = FunctionImpl.make(
  api,
  "notes",
  "create",
  ({ text }) =>
    Effect.gen(function* () {
      const writer = yield* DatabaseWriter;
      return yield* writer.table("notes").insert({ text });
    }).pipe(Effect.orDie),
);
Implementation files should mirror the structure of your spec files for easy navigation.

tables/

Table definitions use Effect schemas to define your database structure:
tables/Notes.ts
import { Table } from "@confect/server";
import { Schema } from "effect";

export const Notes = Table.make({
  name: "notes",
  Fields: Schema.Struct({
    text: Schema.String,
    userId: Schema.optionalWith(Schema.String, { exact: true }),
  }),
  Indexes: Table.indexes({
    by_creation_time: ["_creationTime"],
    by_user: ["userId"],
  }),
});

Root Files

spec.ts

The root specification file combines all your function specs:
spec.ts
import { Spec } from "@confect/core";
import { notes } from "./spec/notes";
import { users } from "./spec/users";

export default Spec.make()
  .add(notes)
  .add(users);

impl.ts

The root implementation file combines all your function implementations:
impl.ts
import { Impl } from "@confect/server";
import { Layer } from "effect";
import api from "./_generated/api";
import { notes } from "./impl/notes";
import { users } from "./impl/users";

export default Impl.make(api).pipe(
  Layer.provide(Layer.mergeAll(notes, users)),
  Impl.finalize,
);

schema.ts

The database schema file combines all your table definitions:
schema.ts
import { DatabaseSchema } from "@confect/server";
import { Notes } from "./tables/Notes";
import { Users } from "./tables/Users";
import { Tags } from "./tables/Tags";

export default DatabaseSchema.make()
  .addTable(Notes)
  .addTable(Users)
  .addTable(Tags);

convex/ Directory

The convex/ directory contains Convex-specific files:
convex/
├── _generated/          # Generated by Convex CLI (do not edit)
│   ├── api.d.ts
│   ├── dataModel.d.ts
│   └── server.d.ts
├── schema.ts            # Convex schema (generated from Confect)
├── http.ts              # HTTP endpoints (optional)
└── crons.ts             # Cron jobs (optional)

schema.ts

This file is generated by the Confect CLI from your confect/schema.ts:
convex/schema.ts
import { ConvexSchemaToDataModel } from "@confect/server/SchemaToValidator";
import { defineSchema } from "convex/server";
import confectSchema from "../confect/schema";

export default defineSchema(
  ConvexSchemaToDataModel(confectSchema),
);
While this file is generated, it’s safe to add additional Convex-specific configuration here if needed.

HTTP Endpoints

For HTTP endpoints, you can use Effect’s HTTP API modules:
convex/http.ts
import { httpAction } from "convex/server";
import { HttpApi } from "@confect/server";
import httpApi from "../confect/http";

export default HttpApi.toConvexHttpRouter(httpAction, httpApi);

Grouping Functions

Confect supports hierarchical function organization using GroupSpec:
spec/notes.ts
import { GroupSpec } from "@confect/core";
import { create } from "./notes/create";
import { list } from "./notes/list";
import { update } from "./notes/update";
import { delete_ } from "./notes/delete";

export const notes = GroupSpec.make("notes")
  .addFunction(create)
  .addFunction(list)
  .addFunction(update)
  .addFunction(delete_);
This creates a logical grouping: notes.create, notes.list, etc.

Nested Groups

You can nest groups for deeper organization:
spec/admin.ts
import { GroupSpec } from "@confect/core";
import { users } from "./admin/users";
import { settings } from "./admin/settings";

export const admin = GroupSpec.make("admin")
  .addGroup(users)
  .addGroup(settings);
This creates paths like: admin.users.list, admin.settings.update

File Naming Conventions

PascalCase

Table definitions: Users.ts, Notes.ts

camelCase

Functions and groups: create.ts, users.ts

lowercase

Directories: spec/, impl/, tables/

Reserved

Root files: spec.ts, impl.ts, schema.ts

Example Project

Here’s a complete example of a small project structure:
my-app/
├── confect/
│   ├── _generated/
│   │   ├── api.ts
│   │   ├── refs.ts
│   │   └── services.ts
│   ├── spec/
│   │   ├── notes.ts
│   │   └── users.ts
│   ├── impl/
│   │   ├── notes.ts
│   │   └── users.ts
│   ├── tables/
│   │   ├── Notes.ts
│   │   └── Users.ts
│   ├── spec.ts
│   ├── impl.ts
│   └── schema.ts
├── convex/
│   ├── _generated/
│   ├── schema.ts
│   └── http.ts
├── src/
│   └── App.tsx
└── package.json

Best Practices

Ensure that for every spec file, there’s a corresponding impl file with the same structure.
Group names should reflect your domain: users, posts, comments, not generic names like data or api.
Never manually edit files in _generated/ directories. They will be overwritten by the CLI.

Next Steps

Spec-Impl Model

Understand how specs and implementations work together

Services

Learn about Effect services in Confect

Build docs developers (and LLMs) love