A Next.js app that hosts multiple Custom Field UIs for Contentstack using the App SDK (@contentstack/app-sdk). Each field type has its own URL path so you can register different routes in Developer Hub for different content-type fields.
The home page (/) is a documentation landing page that lists every route and how query strings work. Field routes are meant to load inside the entry editor iframe; opening them in a normal browser tab only shows a “connect from Contentstack” message.
- Node.js 18+ (recommended: current LTS)
- npm (or pnpm/yarn/bun)
npm install
npm run devOpen http://localhost:3000 for the route index, or go directly to a field path (for example http://localhost:3000/text).
npm run build # production build
npm run start # run production server locally
npm run lint # ESLint| Path | Use for | Stored value (conceptually) |
|---|---|---|
/ |
Index and usage notes | — |
/text |
Single-line text | String |
/boolean |
Yes/no | true / false |
/number |
Numeric input | Number or empty |
/date |
Date and time | ISO 8601 string |
/json |
JSON object | Parsed JSON (invalid JSON is not saved) |
/file |
File / asset field | Asset UID string, or comma-separated UIDs for multi-file |
/reference |
Reference field | Array of { uid, _content_type_uid } (modern reference shape) |
Route metadata is also defined in src/config/field-routes.ts (used by the landing page).
Restrict which asset MIME types are allowed after the editor pastes an asset UID. On blur or Enter, the app loads the asset via the SDK and checks content_type.
Examples:
/file?accept=image/png,image/jpeg/file?accept=image/*
Omit accept to allow any asset UID (still validated that the asset exists when an allowlist is used).
Comma-separated content type UIDs allowed for the referenced entry (similar in spirit to multi-type reference configuration in Contentstack and marketplace-style apps).
Examples:
/reference?content_types=blog_post/reference?content_types=blog_post,author
Behavior:
- One UID in the list: that content type is fixed (no CT picker).
- Several UIDs: dropdown to pick the content type.
- None: you type the content type UID manually.
Use Validate & save to run a CMA check (GET /v3/content_types/{ct}/entries/{entry}) before writing the field.
- Create or open an app in Developer Hub.
- Add a Custom Field UI location and set the hosted app URL to your deployed origin plus the path you need, for example:
https://your-domain.example/texthttps://your-domain.example/file?accept=image/*
- In the content type, add a field that uses this custom field and set the field data type to match what the route stores (Text, Boolean, Number, Date, JSON, File, Reference, etc.).
The App SDK only receives stack context when the iframe runs inside the Contentstack UI; local development usually requires a tunnel (ngrok, Cloudflare Tunnel, etc.) so Developer Hub can load https URLs.
@contentstack/app-sdk—ContentstackAppSDK.init(), thensdk.location.CustomFieldforfield.getData/field.setData,frame.enableAutoResizing(), andsdk.setReady().- No SSR for the SDK — field UI is loaded with
next/dynamicandssr: falsebecause the SDK expects a browser environment at module load. - Shared context —
src/context/CustomFieldContext.tsxinitializes the SDK once per field view; individual field components live undersrc/components/fields/.
src/
app/ # App Router pages (/, /text, /file, …)
components/
field-kit/ # FieldAppRouter, FieldEntry (dynamic loader)
fields/ # Per–field-type UI (TextField, FileField, …)
config/field-routes.ts
context/CustomFieldContext.tsx
lib/ # Helpers (query parsing, MIME matching)
Private / internal use unless you add a public license.