Documentation Index
Fetch the complete documentation index at: https://confect.dev/llms.txt
Use this file to discover all available pages before exploring further.
Installation
pnpm add convex @confect/core @confect/server @confect/cli @confect/react
Usage
Set up your Convex dev deployment
Run convex dev to set up your Convex dev deployment.
Define your database schema
Not every Effect Schema is valid for use in Confect. See
Schema Restrictions for more
information about what’s permitted and what’s not. Define a table.import { Table } from "@confect/server";
import { Schema } from "effect";
export const Notes = Table.make(
"notes",
Schema.Struct({
text: Schema.String,
}),
);
And then add it to your database schema.import { DatabaseSchema } from "@confect/server";
import { Notes } from "./tables/Notes";
export default DatabaseSchema.make().addTable(Notes);
Define your Confect API spec
Create a GroupSpec and add some functions to it.import { FunctionSpec, GroupSpec } from "@confect/core";
import { Schema } from "effect";
import { Notes } from "./tables/Notes";
export const notes = GroupSpec.make("notes")
.addFunction(
FunctionSpec.publicQuery({
name: "list",
args: Schema.Struct({}),
returns: Schema.Array(Notes.Doc),
}),
)
.addFunction(
FunctionSpec.publicMutation({
name: "create",
args: Schema.Struct({ text: Schema.String }),
returns: Schema.Null,
}),
);
Add the GroupSpec to your API’s Spec.import { Spec } from "@confect/core";
import { notes } from "./notes.spec";
export default Spec.make().add(notes);
Run the codegen command
Generate your app’s Confect API, services, and registered functions. Implement your Confect functions
Create a GroupImpl and implement its functions.import { FunctionImpl, GroupImpl } from "@confect/server";
import { Effect, Layer } from "effect";
import api from "./_generated/api";
import { DatabaseReader, DatabaseWriter } from "./_generated/services";
const list = FunctionImpl.make(api, "notes", "list", () =>
Effect.gen(function* () {
const reader = yield* DatabaseReader;
return yield* reader
.table("notes")
.index("by_creation_time", "desc")
.collect();
}).pipe(Effect.orDie),
);
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),
);
export const notes = GroupImpl.make(api, "notes").pipe(
Layer.provide(list),
Layer.provide(create),
);
Add the GroupImpl to your API’s Impl, and finalize it.import { Impl } from "@confect/server";
import { Layer } from "effect";
import api from "./_generated/api";
import { notes } from "./notes.impl";
export default Impl.make(api).pipe(
Layer.provide(notes),
Impl.finalize,
);
Start your Confect app
Run the confect dev command to generate your app’s Convex functions.In another terminal, run the convex dev command to start your Convex dev deployment. Call your Confect functions from your React app
Set up the Convex React client and provider.import { ConvexProvider, ConvexReactClient } from "convex/react";
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const convexClient = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL);
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<ConvexProvider client={convexClient}>
<App />
</ConvexProvider>
</React.StrictMode>,
);
Use Confect’s React hooks alongside your Confect public refs to call your Confect functions.import { useMutation, useQuery } from "@confect/react";
import { Array } from "effect";
import { useState } from "react";
import refs from "../confect/_generated/refs";
const App = () => {
const notes = useQuery(refs.public.notes.list, {});
const createNote = useMutation(refs.public.notes.create);
const [newNote, setNewNote] = useState("");
return (
<div>
<ul>
{notes === undefined
? <p>Loading…</p>
: Array.map(notes, (note) => (
<li key={note._id}>{note.text}</li>
))}
</ul>
<br />
<textarea
rows={4}
cols={50}
value={newNote}
onChange={(e) => setNewNote(e.target.value)}
/>
<br />
<button
onClick={() =>
void createNote({ text: newNote }).then(() => setNewNote(""))
}
>
Create note
</button>
</div>
);
};
export default App;
Example project
See a full, working example project here.