> ## Documentation Index
> Fetch the complete documentation index at: https://confect.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Functions

> Define and implement Convex queries, mutations, and actions with Confect.

Confect functions are defined as a [spec and impl](/concepts/spec-impl-model) pair. The spec declares each function's name, arguments, and return type. The impl provides the handler logic.

## Function types

| Constructor                     | Description                |
| ------------------------------- | -------------------------- |
| `FunctionSpec.publicQuery`      | Public query function      |
| `FunctionSpec.publicMutation`   | Public mutation function   |
| `FunctionSpec.publicAction`     | Public action function     |
| `FunctionSpec.internalQuery`    | Internal query function    |
| `FunctionSpec.internalMutation` | Internal mutation function |
| `FunctionSpec.internalAction`   | Internal action function   |

For Node.js actions, see [Node Actions](/server/node-actions). To integrate plain Convex functions (for use with Convex components or other libraries), see [Plain Convex Functions](/server/plain-convex-functions).

## Defining a spec

Each function spec defines the function's name, arguments schema, and returns schema. The `args`, `returns`, and (optional) `error` schemas are passed as `() => Schema` callbacks, evaluated lazily the first time the function is invoked. Function specs are added to a `GroupSpec` and default-exported from a `*.spec.ts` file. See [The Spec/Impl Model](/concepts/spec-impl-model) for a full walkthrough.

```ts confect/notes.spec.ts theme={null}
import { GroupSpec, FunctionSpec } from "@confect/core";
import * as Schema from "effect/Schema";

import notes from "./_generated/tables/notes";

const list = FunctionSpec.publicQuery({
  name: "list",
  args: () => Schema.Struct({}),
  returns: () => Schema.Array(notes.Doc),
});

export default GroupSpec.make().addFunction(list);
```

Run `confect codegen` after adding or changing specs.

### Typed errors

A spec can also declare an optional `error` schema. When it does, the corresponding handler's `Effect` error channel is typed as that schema, and the failure is decoded for callers at every call site (React hooks, JS clients, and tests). See [Error Handling](/server/error-handling) for the full walkthrough.

```ts theme={null}
import { FunctionSpec } from "@confect/core";
import * as Schema from "effect/Schema";

import { Id } from "./_generated/id";
import notes from "./_generated/tables/notes";

class NoteNotFound extends Schema.TaggedError<NoteNotFound>()("NoteNotFound", {
  noteId: Id("notes"),
}) {}

FunctionSpec.publicQuery({
  name: "getOrFail",
  args: () => Schema.Struct({ noteId: Id("notes") }),
  returns: () => notes.Doc,
  error: () => NoteNotFound,
});
```

## Implementing functions

Each function impl contains a handler that implements the function's logic. Function impls are composed into group impls using Effect layers.

The handler receives the decoded arguments as its first parameter and returns an `Effect`. Use the generated [services](/concepts/services) (like `DatabaseReader`, `DatabaseWriter`, `Auth`, etc.) inside your handler to interact with Convex.

```ts confect/notes.impl.ts theme={null}
import { FunctionImpl, GroupImpl } from "@confect/server";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";

import databaseSchema from "./_generated/schema";
import { DatabaseReader } from "./_generated/services";
import notes from "./notes.spec";

const list = FunctionImpl.make(databaseSchema, notes, "list", () =>
  Effect.gen(function* () {
    const reader = yield* DatabaseReader;

    return yield* reader
      .table("notes")
      .index("by_creation_time", "desc")
      .collect();
  }).pipe(Effect.orDie),
);

export default GroupImpl.make(databaseSchema, notes).pipe(
  Layer.provide(list),
  GroupImpl.finalize,
);
```

`GroupImpl.finalize` is the per-group completeness check: it only typechecks once every function declared by the spec has been provided to the group layer.

<Note>
  Convex bundles a deployment into a single artifact, but a function's cold
  start only evaluates the module graph reachable from its entry point. Confect
  emits one Convex module per group, so cold-starting a function only evaluates
  its own group's spec, impl, and the tables it touches. To keep that cold start
  fast, import Effect from its submodule paths (`import * as Schema from
      "effect/Schema"`) rather than the `effect` barrel in your `confect/` files—a
  barrel import pulls the whole `Schema` namespace into the module graph your
  function evaluates at cold start, even when you use only a small part of it.
</Note>
