What's new
Every release, what changed and why it matters.
- Rebuild the dashboard on React Aria Components, with keyboard navigation, focus management and screen reader support throughout, a new theme with dark mode, a responsive layout, entry history and a references panel that shows which entries link to the current one. The entry sidebar starts closed for entries without a preview.
- Add
alinea/components, the public component library the dashboard is built from, to build custom fields and views. It includesStack,Form(field errors from native constraints,validationErrorsor whatonSubmitreturns) anduseAsyncListto load items page by page or as you type, and to update, remove or add loaded items without loading them again.DialogContentsubmits a form withonSubmit,DialoghasonClose,TablehasloadingandonLoadMore,ComboBoxhas groups, item descriptions and icons,filterandloading, andTextFieldhasmaxRows,inputModeandpattern. Collection keys are strings or numbers. Dashboard icons are available fromalinea/dashboard/icons. - The theme tokens and resets of
alinea/cssapply inside elements withdata-alinea-theme, which the dashboard sets on<html>, so the stylesheet can be loaded on a site without restyling it. The workspace color is--alinea-workspace-color. - Add
alinea/cmsfor custom fields and views: field hooks that read and write the fields of the row, a parent row or the entry when passed that field (useFieldValuealso takes the key of a field of the row),useEntry()returning aDashboardEntry,useNavigateto open entries by id,EditFieldandEditFields(also for the fields of an object field),FieldChromeandEntryTable.href({entryId})fromalinealinks to an entry in the dashboard, also outside of it. The entry editor sets--alinea-header-height.useSiblingFieldValueand theuseFieldhooks ofalinea/dashboardare deprecated, theuseEntryEditorshim reads the publish status fromactiveVersion.status. - Add
i18n: {translate: 'fields'}to keep a single entry per item in a translated root, andField.localisedto keep every locale of a value in a single field, with fallbacks. Withoutlocalesit takes the locales of the root of its entry and throws in roots that translate entries, withlocalesit works in any root. Queries for a locale find the entries of roots that translate fields to it, files of the media root still only match queries without a locale.Field.localiseris deprecated. - Add
Config.fileto define types of uploaded files, with fields of their own and anacceptlist, and upload into any root or folder that contains them. An upload becomes the first file type that accepts it, the upload dialog asks which one when several do. Image and file fields pick files of every file type, the media root is built on theMediaFilefile type. Uploads to a location without file types still become media files, theupload_fileMCP tool takes arootandtype. - Add
tabstoConfig.type,Config.documentandConfig.file, and aviewtoField.tab, eg. an Analytics tab that shows a custom component. Entries show the tabs in the entry editor, list rows and rich text blocks as sections of their settings sheet, below the label and anchor. Their fields are stored and queried like the other fields. - Define
MediaFilein the schema withConfig.mediaFileto give media files tabs or fields of your own. Files uploaded before have them too, and queries namingMediaFilefind it. - Define
MediaLibraryin the schema withConfig.mediaLibraryto change the overview of media folders, or give them tabs or fields of your own.Config.mediaOverview()returns the built-in overview to reuse and extend its columns, sorts and filters. - Add the
overviewoption to container types and roots to configure how the dashboard lists their children: columns (Config.column) with per-type selects, formatting and custom cells, built-in type, status, updated and author columns, sorting by column header (kept in the URL), the defaultsort,layout, cardthumbnailand toolbaractions. A columnheaderis text or a React element, andinfoexplains the column in a popover opened from an info button next to the header. Filters can load their options from the content with a function that receives thegraphandlocale.tabslist the entries of a filter per tab above the list (the selected tab is kept in the URL), andheaderrenders a view between the toolbar and the list, eg. totals of the listed entries. The media library lists previews, dimensions, sizes and file types.EntryTableinalinea/cmsrenders the same columns in custom views.overview.sortreplacesorderChildrenBy,summaryRowandsummaryThumbare deprecated and theoverviewfield option only applies when the parent defines no columns. - Add the
actionstype option: components in the entry header, next to the publish button. - A type's
viewreplaces the form below the entry header instead of the whole editor: the field hooks ofalinea/cms,EditFieldandEditFieldsedit the fields of the entry, the header publishes or saves them as a draft, the sidebar shows history and references, and leaving with unsaved changes asks to confirm.viewalso accepts a component instead of a path. - The
collapsed: falsetype option expands an entry's children in the sidebar content tree from the start. - Add
widthto the options of every field, and fixField.createtyping for options that extendFieldOptions. - Query the entries that link to an entry with
Query.referencedBy, eg.select: {products: Query.referencedBy({type: Product, field: Product.brand})}, count them withcount: true(overview columns that count are sortable) and filter on them:filter: {_referenced: Query.referencedBy({type: Product, filter: {active: true}})}. - Select fields inside object fields in queries, such as
select: {title: Page.seo.title}, also in relations likeQuery.childrenand inorderBy. - Bundle a SQLite content database with full text fuzzy search. Search matches
the hyphenated, spaced and joined spellings of a word:
multi-modal,multi modalandmultimodalall find each other. Date and number fields are indexed per type that has them, which keeps these indexes small. - Show the progress of the content sync below the dashboard's loading spinner
(
Syncing content · 1,240 of 4,800 files) and in the activity status for later syncs.syncWithtakes anonProgresscallback. - Record URL aliases in the metadata field when an entry's URL changes, and
resolve them in queries (
aliasfilter,Query.aliases). The metadata field also storescreatedAt,createdBy,updatedAtandupdatedBy. - Roles combine per role: a deny only applies within the role that sets it, so another role of the same user can still allow the action. Before, a deny in any role blocked it for the user.
- Enforce the
explorepermission: link and image pickers list the entries a role can explore, without opening them in the dashboard. Allowingreadallowsexplore, denyingreaddenies it unlessexploreis allowed. - Target fields inside object fields in role permissions, such as
{field: Article.visibility.germany, deny: {all: true}}. - Add
beforeCommitandafterCommithandler hooks to rewrite changes before they are committed, or to revalidate, notify and deploy after. Both receive theuserthat commits,afterCommitalso the committedentriesand theremovedentries with the url they had.alinea dev --role <name>signs in the local user with that role, for saves, hooks andcms.user(). - Publish instantly: deployed sites sync new content as soon as it is committed,
driven by the repository sha.
syncIntervalis now a fallback, defaulting to 60 seconds. - Commits from the dashboard end with an
Alinea-Contenttrailer holding the content sha they commit, so a deploy can skip building a publish that only changed content, see the instant publishing guide. - Add an MCP server to
alinea dev(http://localhost:4500/mcp) so coding agents can read the schema and create, edit, publish, move and delete entries and upload media through the dashboard's save path. - Add the
adminPath,maxUploadSizeandtracerconfig options, and a workspacemediaUrloption. - Add
Field.select.multiple,minandmaxfor lists, images and link options in rich text, rich text anchors, link anchors and suffixes, andallowDuplicatesfor links. - Add a composable backend in
alinea/backend(createBackend,auth,database,github,uploads) with S3 and Supabase uploads and user management. - Require Node.js 24 or higher and React 19.
- Require
handlerUrlin the config, and a productionbaseUrlunlesshandlerUrlis absolute: server renders reach the handler through it.dashboardFileis deprecated in favor ofadminPath. - Serve media files through
${adminPath}/file/...on the site: image and file links now return that URL instead of the stored location. Image links only havesrc, theirurlproperty is removed.alinea buildwarns about media files with a url as location andalinea build --fixrepairs them. - Change
Config.media()to take root options, children move tochildren. - Remove the options of
Field.metadata()and thestepoption ofField.time(). - Move the rich text editor to Tiptap 3.
extensionsis now a function that receives the default extensions,defaultToolbartakes an options object. - Change
Edit.moveto{id, target, dropPosition}. - Remove the
remotehandler option and the unused entry hooks. OAuth2 backends requirevalidateClaims. Drafts are no longer stored in the database. - Remove the components from
alinea/uiexceptRichText, and the form atoms fromalinea/dashboard. - Fix read-only roles for nested fields and upload permissions in nested media folders.
- Fix the locale of translations created in another root.
- Fix bundled content being served stale right after a cold start.
- Verify signed Alinea Cloud handshake requests and pin preview messages to the dashboard origin.
- Fix rich text parsing of marks around images and keep
data-attributes on rich text nodes. - Fix
alinea buildkeeping a config watcher alive while the forwarded command runs, and a live preview refreshing twice in React strict mode.
- Add user roles and permission policies. Permissions can now be scoped by workspace, root, type, field, entry id and locale, and cover actions such as create, read, update, delete, reorder, move, publish, archive, upload and explore. The dashboard and backend now enforce these policies.
- Add configurable rich text toolbars and custom Tiptap extension support.
- Improve the Next.js integration.
withAlineanow uses the CLI-provided admin path, proxies the dashboard in development, rewrites to the generated dashboard in production and supports customdashboardFilevalues. - Allow
baseUrlto be configured per environment. - Add workspace and root information to
EntryUrlMeta. - Return CORS headers for local uploads.
- Improve OAuth and JWT handling with explicit SameSite cookies, access-token refresh without treating refresh tokens as JWTs, stricter JWKS key selection and optional extra claim validation.
- Fix rich text HTML parsing so marks are applied across nested content and root-level whitespace is ignored.
- Filter unresolved entry links from multi-link query results.
- Add
llms-full.txtto the published package.
- Don't use Y.js for preview deltas, but a more predictable diff
- Fix link order in rich text fields
- Fix search results turning up empty
- Show children indicator in tree even if all children are untranslated
- Previous release mistakenly included features that were not ready for release.
- Refactor how we build the internal index of all entries. This is now done immutably so that any problems during mutations to entries do not corrupt the index.
- Add more richtext table options (mergeCells, splitCell, toggleHeaderCell and toggleHeaderColumn)
- Fix Query.next and Query.previous which were not sorted correctly
- Set access token at the root so
cms.user()calls work in preview environments
- Prefix upload locations with media dir for self-hosted backends
- Handle logout endpoint for OAuth backends
- Handle authentication with Alinea Cloud using OAuth 2.0
- Enable ctrl and middle mouse clicks in the entry tree to open in new tab
- Use a shared EventSource in dev mode to avoid the browser maximum of 6 connections per origin
- Check workspace and root properties during entry creation
- Fix: handle missing blobs in local IndexedDB store
- Fix: data coming from Alinea Cloud was not handled correctly
- Fix: previous release was published with extraneous dependencies
- Disabled arrow up/down when on first/last row in lists (#450)
- Keep copy icon visible during drag state; disable icons while dragging (#451)
- SelectField: responsive layout improvements (#448)
- ImageView: show cursor crosshair (#449)
- Collapsible list rows (#444)
- IconButton: focus layout change (#447)
- TextField: added placeholder support (#442) and type email, tel, text, or url (#445)
- Remove web workspace; move website to alineacms/alineacms.com
- Fix: don't bundle contents in edge functions
- Fix: order results of Query.parents by level
- Fix: respect parent insert order on create
- Fix: internal links to image and file entries from the link preview
- Fix: publishing changes to file details no longer removes the associated file
- Fix: don't use transparency in averageColor property for images
- The previous release mistakenly added
nextas a direct dependency to thealineapackage. While we're currently focused on providing a clean Next.js integration, Alinea is not tied to Next.js and should not depend on it.
- Using the
alinea initcommand for a Next.js website will now auto-create the handler route inapp/(alinea)/api/cms/route.ts. The generatedcms.tsconfig file also includes more default options such as thebaseUrlandhandlerUrl.
- Restore drag-drop behavior in entry tree. The drag and drop functionality was broken in the previous release due to a change in the way entries are rendered in the sidebar.
- Better support for drafts in Alinea. Drafts can be enabled using the config
option
enableDrafts: true. Drafts and archived entries will now show their status in the sidebar as well. Workflows are adjusted to be able to create a draft entry, including draft children. These will show up as "unpublished" and can be published in one go. Further stability improvements were made to updating entry statuses.
- Fix usage of cms.user() in api routes
- Stability improvements.
- Fix use of the readOnly field property which was overwritten from context
- Minor fixes to path field
- Make sure the editor widget doesn't interfere with pointer events of underlying elements
- Added a preview property to TypeConfig to disable the preview on Type level (#407)
- UI tweaks
- Archiving an entry results in archived children entries as well.
- Adjust the inferred results of
cms.findandcms.getso they work reliable in non-strict Typescript codebases as well.
- Fix the query result type of
Query.parent,Query.nextandQuery.previouswhich were incorrectly typed as anArray.
- Add a copy and paste button to List field blocks
- Update link properties condition and location to be dynamic. The contents can be set by using a function.
- Fix navigation tree in link picker
- Set the default depth of querying children to 1
- Fix handling mutation retries based on the http status code received.
- Fix skip/take for queries which were not used
- Disable navigation in the internal link picker if a condition is used
- Fix live previews for translated entries
- Fix querying linked entries without locale
- Fix querying linked entries - the requested locale was not passed
- Alinea will now fail if linked entries cannot be resolved during querying. Before it would log the error but continue - but this is rarely desired.
Fix removing field contents in
Edit.update. Pass an undefined value to remove field contents:await cms.commit( Edit.update({ id: '...', set: {removeMe: undefined} }) )- Fix processing link data correctly even it contains legacy data
- Only access normalized config in next cms adapter. This fixes an error in production builds which would prevent you from querying media files.
- Tweak the withAlinea config function to work in all environments including Next 14.
Add the Infer.Entry and Infer.ListItem types which can be used to infer the type of an entry or list item from a query.
type Entry = Infer.Entry<typeof EntryType> const entry: Entry = await cms.get({type: MyType}) type ListItem = Infer.ListItem<typeof ListType> const list: Array<ListItem> = await cms.get({select: MyType.list})
- Add support for Next.js 15 and Turbopack.
- Removed all previously deprecated options.
- Next.js config changes are now bundled in a
withAlineaexport found in 'alinea/next'. - Querying via
cms.find/getis rewritten to take a single query object. Have a look at the docs to see how to use the new query api. - Creating custom fields can now be done through
Field.create. - Entries now have a single id. If you are upgrading and were using i18n you
can stabilize your ids by running
npx alinea build --fix.