How to Create Custom Collections in the Instatic Data Workspace

The Instatic data workspace enables custom collection creation through a React dialog component that submits table schemas to a persistence layer, instantiating new data tables via the createCmsDataTable API.

The Instatic admin panel provides a Data Workspace for managing dynamic content structures. This article explains how developers and content managers can create custom collections—essentially new database tables with defined schemas—through the coordinated interaction of UI components and persistence hooks. According to the CoreBunch/Instatic source code, this process centers on the NewTableDialog component and the useDataWorkspace hook.

Architectural Flow for Creating Custom Collections

The data workspace follows a strict unidirectional flow to ensure type safety and atomicity when creating custom collections.

Step 1: Initiating Creation via DataSidebar

The entry point begins in src/admin/pages/data/DataPage.tsx, where the workspace initializes the useDataWorkspace hook to load existing tables. The left-hand DataSidebar component renders a "Create collection" button that toggles the dialog state.

// In src/admin/pages/data/DataPage.tsx
const [newTableDialogOpen, setNewTableDialogOpen] = useState(false);

// Button rendered via DataSidebar
<Button onClick={() => setNewTableDialogOpen(true)}>Create collection</Button>

Step 2: Schema Composition in NewTableDialog

When triggered, src/admin/pages/data/components/NewTableDialog/NewTableDialog.tsx renders a modal that collects the collection name and field definitions. It utilizes the shared FieldSchemaComposer component to build the initial schema array before submission.

// In src/admin/pages/data/components/NewTableDialog/NewTableDialog.tsx
export function NewTableDialog({ open, onClose, tables, onCreate }) {
  const [name, setName] = useState('');
  const [fields, setFields] = useState<FieldDefinition[]>([]);

  const handleSubmit = async () => {
    await onCreate({
      name,
      slug: slugify(name),
      fields, // Array generated by FieldSchemaComposer
    });
    onClose();
  };

  return (
    <Dialog open={open} onClose={onClose}>
      <DialogTitle>Create collection</DialogTitle>
      <FieldSchemaComposer fields={fields} onChange={setFields} />
      <Button onClick={handleSubmit}>Create</Button>
    </Dialog>
  );
}

Step 3: Persistence via createCmsDataTable

Upon confirmation, the dialog invokes workspace.createTable(), which calls createCmsDataTable() from the @core/persistence layer. This function inserts a new row into the data_tables database table and returns the created metadata.

Step 4: Reactive State Updates

The useDataWorkspace hook updates its local tables state with the new entry, clears existing rows, and sets the newly created table as selected, ensuring the UI reflects the new collection immediately.

// In src/admin/pages/data/hooks/useDataWorkspace.ts
const createTable = async (input: CreateDataTableInput): Promise<DataTable> => {
  setTablesError(null);
  const table = await createCmsDataTable(input); // Persistence layer call
  setTables((current) => [...current, { ...table, rowCount: 0 }]);
  setSelectedTableId(table.id);
  setRows([]);
  setSelectedRowId(null);
  return table;
};

Implementation Code Examples

Consuming the Workspace Hook

Components access the creation logic through the useDataWorkspace hook, which isolates table management from presentation layers.

const workspace = useDataWorkspace({ shouldLoadRows: true });

const handleCreate = async (input) => {
  await workspace.createTable(input); // Creates the custom collection
};

Handling Field Defaults

The workspace imports utility functions from src/admin/pages/data/utils/fieldDefaults.ts to generate default values for new fields, ensuring consistency across collections.

Key Source Files and Functions

Summary

  • The Data Workspace creates custom collections by combining React UI components with a typed persistence layer.
  • NewTableDialog handles user input and schema composition before submitting to the useDataWorkspace hook.
  • The createCmsDataTable function in the persistence layer handles the actual database insertion, ensuring atomic table creation.
  • State management automatically updates the UI, selects the new collection, and clears stale row data to prevent inconsistencies.
  • File paths like src/admin/pages/data/components/NewTableDialog/NewTableDialog.tsx and src/admin/pages/data/hooks/useDataWorkspace.ts define the critical integration points.

Frequently Asked Questions

What is a custom collection in Instatic?

A custom collection in Instatic represents a dynamically created data table defined in the data_tables schema. It consists of a unique slug, display name, and an array of field definitions that determine the structure of content entries stored within that collection.

How does the FieldSchemaComposer contribute to collection creation?

The FieldSchemaComposer component renders the UI for defining initial fields (such as text, number, or boolean types) before the collection is created. It generates the fields array passed to createTable, ensuring the new collection has a valid schema immediately upon instantiation.

Is the collection creation process atomic?

Yes. The creation process is atomic because createCmsDataTable handles both the database insertion and metadata return in a single operation. The useDataWorkspace hook only updates local React state after receiving confirmation from the persistence layer, preventing partial or failed creation states from appearing in the UI.

Can I customize the collection after initial creation?

Absolutely. After creation, the collection appears in the DataSidebar and can be selected for editing. The workspace supports schema modifications through the FieldSchemaComposer and allows adding, editing, or deleting rows via the data inspector panel, all synchronized through the same useDataWorkspace hook.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →