Adding a field type to Nextly

SkillDev tools

Use when adding a new field type to Nextly (a new entry in the FieldType union, a new field factory, or a new schema-builder picker type), or when a field type renders or stores incorrectly across the config, catalog, column-mapping, or admin layers.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Adding a field type to Nextly skill

What this skill tells your AI

The instructions your AI receives, as published by nextlyhq/nextly in .claude/skills/adding-a-field-type/SKILL.md and read by ahel’s review.

You might not need this

If the field type belongs to ONE plugin, do not touch core. Declare it in the plugin's contributes.fieldTypes (PluginFieldType: type id, storage primitive text|longText|boolean|number|timestamp|json, admin component path, optional surfaces). The boot-time registry (packages/nextly/src/domains/schema/field-types/field-type-registry.ts) validates it, and the admin renders it via the component registry. The rest of this skill is for BUILT-IN types only.

The end-to-end recipe (built-in type)

Work through these in order; each layer has tests nearby to extend.

  1. Type union + config interface
    • Add the literal to FieldType in packages/nextly/src/collections/fields/types/base.ts.
    • Create packages/nextly/src/collections/fields/types/<type>.ts with the config interface; export it from types/index.ts (this also feeds ALL_FIELD_TYPES).
  2. Factory: add the helper in packages/nextly/src/collections/fields/helpers.ts following the existing (config) => ({ ...config, type: "<type>" }) shape with a JSDoc example.
  3. Type guard: add it in collections/fields/guards.ts via createTypeGuard, and decide membership in isDataField / isRelationalField / hasNestedFields.
  4. Accepted-type lists (two of them, both hand-maintained):
    • VALID_FIELD_TYPES in packages/nextly/src/shared/base-validator.ts — the config gate. Miss this and defineCollection throws FIELD_TYPE_INVALID at boot even though every other layer is wired.
    • DynamicFieldType in packages/nextly/src/schemas/dynamic-collections/legacy-types.ts — the shape of a Schema-Builder-stored field definition.
  5. Catalog entry: add to FIELD_TYPE_CATALOG in collections/fields/catalog.ts (label, category, hint, Lucide icon NAME as a string). Pickers render from the catalog automatically. If the type should appear on the user-fields or form surfaces, add it to those allow-lists too; if it is surface-only, do NOT add it to the canonical union (see the catalog's comment block for why).
  6. Column mapping (the single source of truth): add the per-dialect case in packages/nextly/src/domains/schema/services/field-column-descriptor.ts. Then verify the descriptor's kind is handled by runtime-schema-generator.ts, pipeline/diff/build-from-fields.ts, and the DDL emitters in domains/schema/pipeline/ddl-emitter/.
  7. Validation: add a validator under collections/fields/validators/ and the case in domains/schema/services/zod-generator.ts (the per-type switch).
  8. Type generation: add the TS mapping in domains/schema/services/type-generator.ts so nextly generate:types emits the right property type.
  9. Admin rendering:
    • Edit view: a component under packages/admin/src/components/features/entries/fields/ and its case in FieldRenderer.tsx.
    • List view: cell rendering in the EntryList table components (EntryTableCell.tsx / EntryTableColumns.tsx).
    • Builder config: if the type has builder-editable options, extend the schema builder's field editor sheet under packages/admin/src/components/features/schema-builder/.
  10. Serialization extras (check, usually small): the collection export service (domains/collections/services/collection-export-service.ts) and domains/schema/services/schema-hash.ts.

Verify before opening the PR

  • Unit tests at each touched layer (factory, guard, descriptor, zod, type generator) plus an integration test that creates a collection using the type. Because this workflow changes per-dialect column mappings and DDL, cover Postgres plus at least one of MySQL/SQLite (the CI matrix runs all three).
  • pnpm --filter playground nextly generate:types output includes the new type correctly; the field renders in the playground admin (both light and dark).
  • Run the schema-hash and export tests; a new type that changes hashing semantics needs a deliberate decision, not an accidental one.
  • One changeset covering all packages (patch, alpha rules) since this touches published code.

Signals

GitHub stars
57
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
adding-a-field-type
Source
github.com/nextlyhq/nextly