## What
Key-value storage for applications, as proposed in
twentyhq/core-team-issues#2391 — built on the existing `keyValuePair`
entity:
- Nullable `applicationId` relation on `keyValuePair` + a new
`APPLICATION_VARIABLE` type (fast instance command included)
- GraphQL CRUD on the metadata schema (`appKeyValue`, `setAppKeyValue`,
`deleteAppKeyValue`), requiring an `APPLICATION_ACCESS` token —
`applicationId` always comes from the token, never from arguments, so
apps can't touch each other's entries
- `kv.get` / `kv.set` / `kv.delete` helpers in
`twenty-sdk/logic-function`
## Scopes
- **`INSTALL`** (default): entries are private to one workspace install;
arbitrary JSON values
- **`GLOBAL`**: entries are shared across every install of the app, with
claim semantics — the value is always the claiming `workspaceId` and
only that workspace can overwrite or delete the key (guarded writes,
race-safe via insert-if-absent)
Since `applicationId` identifies an install (one row per workspace),
GLOBAL entries are stored under the registration owner workspace's
install so all installs of the same app share one namespace.
The GLOBAL scope is what enables cross-workspace webhook routing: e.g.
the Slack app's `serverRoute` resolver (running in the owner workspace)
can resolve `kv.get('slack:team:' + team_id, { scope: 'GLOBAL' })` to
find the workspace that connected that Slack team — without a workspace
being able to hijack another's mapping.
## Follow-ups
- Wire the Slack assistant PR (#22984) to write the claim at connect
time and read it in the events resolver
- `kv.*` access from front components
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/23089?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
Twenty Documentation
Official documentation for Twenty CRM, powered by Mintlify.
🌐 Live Site
Visit the documentation at docs.twenty.com
📚 Content
This repository contains:
- User Guide (46 pages) - Complete guide for Twenty users
- Developers (24 pages) - Technical documentation for developers
- Twenty UI (25 pages) - UI component library documentation
🚀 Local Development
To run the documentation locally:
# From the twenty monorepo root
npx nx run twenty-docs:dev
The documentation will be available at http://localhost:3000
📝 Editing Content
Adding/Editing Pages
-
Edit MDX files in the appropriate directory:
user-guide/- User documentationdevelopers/- Developer documentationtwenty-ui/- Component documentation
-
Update
navigation/base-structure.jsonif you need to change the tab/group hierarchy or add/remove pages. This file stays in the repo and is not uploaded to Crowdin. -
Keep the translation template (
navigation/navigation.template.json) in sync by runningyarn docs:generate-navigation-templateafter editing the base structure. This template is the only file that should be pushed to Crowdin. -
For each translated locale pulled from Crowdin, ensure a
packages/twenty-docs/l/<language>/navigation.jsonfile exists. These files contain labels only; page slugs always come from the base structure. -
Run
yarn docs:generateto rebuilddocs.jsonfrom the base structure + translated labels.
MDX Format
All documentation pages use MDX format with frontmatter:
---
title: Page Title
description: Page description
image: /images/path/to/image.png
---
Your content here...
Adding Images
- Place images in the
/images/directory - Reference them in MDX:
 - Or use Mintlify Frame component:
<Frame>
<img src="/images/your-image.png" alt="Description" />
</Frame>
🔧 Configuration
navigation/base-structure.json- Source of truth for tabs, groups, icons, and page slugs (English only, not sent to Crowdin).navigation/navigation.template.json- Generated translation template (labels only) that is uploaded to Crowdin.l/<language>/navigation.json- Locale-specific label files pulled from Crowdin.docs.json- Generated Mintlify configuration (always runyarn docs:generateafter modifying navigation files).package.json- Package dependencies and scripts (docs:generate,docs:generate-navigation-template, …).project.json- Nx workspace configuration
📦 Validation
# Validate the documentation build
npx nx run twenty-docs:validate
🔗 Links
🤝 Contributing
To contribute to the documentation:
- Fork the repository
- Make your changes in the
packages/twenty-docsdirectory - Test locally with
npx nx run twenty-docs:dev - Submit a pull request
📄 License
This documentation is part of the Twenty project and is licensed under AGPL-3.0.