# Configuration (https://form.dimah.dev/docs/configuration)



Options for the server instance, the React client, the fill hook, and a custom `database` adapter.

***

## `dimahForm(config)` [#dimahformconfig]

The primary server instance initializer from `@dimah-form/server`. `database` is required. `@dimah-form/db` is not — `memoryAdapter()` ships in `@dimah-form/server`.

```ts
import { dimahForm } from "@dimah-form/server";

export const form = dimahForm({
  database: memoryAdapter(),
  forms: { ... },
  basePath: "/api/form",
});
```

### Configuration Options [#configuration-options]

| Option                | Type                                  | Required | Default       | Description                                                                                                               |
| :-------------------- | :------------------------------------ | :------- | :------------ | :------------------------------------------------------------------------------------------------------------------------ |
| **`database`**        | `ResponseStore`                       | **Yes**  | —             | Persistence adapter (`memoryAdapter()`, `db(formDb)` from `@dimah-form/db`, or a custom `ResponseStore`).                 |
| **`forms`**           | `Record<string, FormDefinitionInput>` | No       | `{}`          | Catalog of code-authored forms created with `defineForm()`. Feeds `$Infer`.                                               |
| **`fieldTypes`**      | `FieldTypeDefinition[]`               | No       | `[]`          | Custom field type definitions created with `defineFieldType()`.                                                           |
| **`basePath`**        | `string`                              | No       | `"/api/form"` | Base path prefix for HTTP route mounting.                                                                                 |
| **`guard`**           | `DimahFormGuard`                      | No       | `undefined`   | Security callback executed before every query or mutation.                                                                |
| **`hooks`**           | `DimahFormHooks`                      | No       | `{}`          | Pre-write (`onStart`, `onDraft`, `onSubmit`) and post-write (`afterSubmit`, `afterDraft`, `afterDelete`) lifecycle hooks. |
| **`validateAnswers`** | `AnswersValidator`                    | No       | `undefined`   | Custom cross-field validation function running on submit.                                                                 |
| **`plugins`**         | `DimahFormPlugin[]`                   | No       | `[]`          | Server plugins created with `definePlugin()`.                                                                             |
| **`metaSchema`**      | `DimahFormMetaSchema`                 | No       | `undefined`   | Custom Zod schemas for validating `meta` dictionaries on forms and fields.                                                |

***

## `createFormClient<T>(options)` [#createformclienttoptions]

Initializes the typed client runtime from `@dimah-form/react`.

```ts
import { createFormClient } from "@dimah-form/react";
import type { Form } from "@/lib/form";

export const formClient = createFormClient<Form>({
  basePath: "/api/form",
});
```

### Configuration Options [#configuration-options-1]

| Option            | Type                                               | Default            | Description                                                                             |
| :---------------- | :------------------------------------------------- | :----------------- | :-------------------------------------------------------------------------------------- |
| **`basePath`**    | `string`                                           | `"/api/form"`      | Relative URL path prefix matching the server's `basePath`.                              |
| **`baseURL`**     | `string`                                           | `undefined`        | Absolute URL prefix (e.g., `"https://api.example.com/api/form"`). Overrides `basePath`. |
| **`credentials`** | `RequestCredentials`                               | `"same-origin"`    | Fetch credentials policy (e.g. `"include"` for cross-origin cookies).                   |
| **`headers`**     | `HeadersInit \| (() => MaybePromise<HeadersInit>)` | `undefined`        | Static headers or dynamic header generator for auth tokens.                             |
| **`fieldTypes`**  | `FieldTypeDefinition[]`                            | `[]`               | Custom field types matching the server configuration.                                   |
| **`plugins`**     | `DimahFormClientPlugin[]`                          | `[]`               | Companion client plugins created with `defineClientPlugin()`.                           |
| **`fetch`**       | `typeof fetch`                                     | `globalThis.fetch` | Custom fetch implementation for SSR or testing harnesses.                               |

***

## `useFormResponse(options)` [#useformresponseoptions]

Headless React hook for managing fill sessions.

### Options [#options]

| Option             | Type                                 | Required | Description                                                          |
| :----------------- | :----------------------------------- | :------- | :------------------------------------------------------------------- |
| **`snapshot`**     | `FormSnapshot`                       | **Yes**  | Form definition snapshot (retrieved from server).                    |
| **`response`**     | `ResponseRecord`                     | No       | Existing response row to edit or view.                               |
| **`respondentId`** | `string \| (() => string)`           | No       | User identifier for draft ownership.                                 |
| **`resume`**       | `boolean`                            | No       | If `true`, reconnects to the user's latest draft on first write.     |
| **`autosave`**     | `boolean \| { debounceMs?: number }` | No       | Enables debounced background draft saving (default debounce: 600ms). |
| **`validate`**     | `"submit" \| "change"`               | No       | `"submit"` (default) or `"change"` (real-time validation on edit).   |
| **`onStarted`**    | `(record: ResponseRecord) => void`   | No       | Callback invoked after `startResponse` completes.                    |
| **`onSaved`**      | `(record: ResponseRecord) => void`   | No       | Callback invoked after `saveDraft` completes.                        |
| **`onSubmitted`**  | `(record: ResponseRecord) => void`   | No       | Callback invoked after `submitResponse` completes.                   |
| **`onReopened`**   | `(record: ResponseRecord) => void`   | No       | Callback invoked after `reopenResponse` completes.                   |
| **`onAbandoned`**  | `(record: ResponseRecord) => void`   | No       | Callback invoked after `abandonResponse` completes.                  |

***

## The `ResponseStore` Interface [#the-responsestore-interface]

Any database adapter passed to `dimahForm({ database })` must satisfy the following interface:

```ts
interface ResponseStore {
  // Form Definitions
  getForm(idOrSlug: string): MaybePromise<FormSnapshot | undefined>;
  saveForm(
    form: FormSnapshot,
    options?: { expectedUpdatedAt?: string },
  ): MaybePromise<void>;
  deleteForm(id: string): MaybePromise<void>;
  listForms(query?: {
    status?: FormStatus;
    limit?: number;
    offset?: number;
  }): MaybePromise<{
    forms: FormSnapshot[];
    limit: number;
    offset: number;
    nextOffset: number | null;
  }>;

  // Response Sessions
  create(row: ResponseRecord): MaybePromise<void>;
  get(id: string): MaybePromise<ResponseRecord | undefined>;
  save(
    row: ResponseRecord,
    options?: { expectedUpdatedAt?: string },
  ): MaybePromise<void>;
  delete(id: string): MaybePromise<void>;
  listResponses(query?: ListResponsesQuery): MaybePromise<{
    responses: (ResponseRecord | ResponseSummary)[];
    limit: number;
    offset: number;
    nextOffset: number | null;
  }>;

  // Draft Helpers
  findLatestDraft(query: {
    formId: string;
    respondentId: string;
  }): MaybePromise<ResponseRecord | undefined>;
  getOrCreateDraft(row: ResponseRecord): MaybePromise<ResponseRecord>;
}
```

***

## Next Steps [#next-steps]

<Cards>
  <Card title="Field Types Reference" href="/docs/field-types" description="Explore built-in field types, validation rules, and showWhen operators." />

  <Card title="Protocol" href="/docs/protocol" description="Review REST route schemas, parameters, and payload structures." />

  <Card title="Error Codes" href="/docs/errors" description="Inspect machine-readable error codes and field validation issues." />
</Cards>
