Enhanced DX for TypeScript Apps
This guide describes the experimental enhanced developer experience, or Enhanced DX, for building YouTrack apps with TypeScript. Enhanced DX adds file-based routing, generated frontend API types, runtime validation in development mode, and a faster development loop on top of the standard app tooling.
Use this guide to create apps with the experimental TypeScript toolchain. To create a standard JavaScript app, start with the App Quick Start Guide.
With Enhanced DX, you still upload a regular app bundle to YouTrack. However, you author backend handlers in TypeScript and let the toolchain build them for you.
Enhanced DX Benefits
Compared with the standard app scaffolding flow, the Enhanced DX toolchain provides the following additions:
Standard app scaffolding | Enhanced DX scaffolding |
|---|---|
JavaScript backend handlers | TypeScript backend handlers with type checking |
Manual HTTP handler wiring | File-based routing for backend endpoints |
No shared request or response contracts | Generated types for frontend API calls |
Manual upload cycle | Automatic rebuild and upload in watch mode |
Manual setup for handlers, settings, and properties |
|
Frontend rebuild and upload on every change | Optional Vite support for frontend changes that appear immediately in |
Prerequisites
To create a YouTrack app with the Enhanced DX toolchain, you need:
Node.js version 18.20.4 or later installed on your machine
Access to a YouTrack instance where you can upload apps
A permanent token with Update Project permission
Create an App Package
To create an app with the Enhanced DX toolchain, use the standard app generator and select the TypeScript development approach.
To create an app package with Enhanced DX:
Prepare an empty directory for your app.
Run the app generator:
npm create @jetbrains/youtrack-appWhen prompted for the development approach, choose TypeScript (Enhanced DX with file-based routing).
Navigate to the generated app package directory.
Create a
.envfile in the root directory of the app package:YOUTRACK_HOST=https://your-youtrack.example.com YOUTRACK_TOKEN=perm:your-permanent-token
As a result, you have a generated app package that is configured for local development and for uploading the app to your YouTrack instance by using the values stored in the .env file.
To start local development, run the following command. It builds the app and uploads a development version to YouTrack.
Work with the App Package
The generated app package includes separate commands for building the frontend and backend, developing the app locally, and uploading it to YouTrack.
Goal | Command |
|---|---|
Develop locally with immediate frontend updates |
|
Run watch mode with rebuild and upload |
|
Generate backend types only |
|
Build the frontend bundle |
|
Create a production build |
|
Upload the current build with credentials from |
|
Build and upload the app |
|
Build Sequence
The frontend depends on API type definitions that are generated during the backend build. For this reason, when you work with the app package for the first time, you must build the backend before you build the frontend.
The generated files in src/api/ are overwritten during backend builds. Do not edit them manually.
Local Development
When you run npm run dev, the app package is prepared for local development as follows:
Previously generated API files are removed
The backend is built and the API type definitions are generated
A development version of the app is uploaded to YouTrack
A local development server is started on port 9000
Changes in backend files trigger a rebuild and a new upload when needed
Changes in frontend files appear immediately during development
Use npm run watch when you do not want to start the local development server. In that mode, frontend changes trigger a regular rebuild and upload instead of appearing immediately.
Package Structure
The generated app package contains the following directories and files. Some files in src/api/ are generated only after you build the backend.
The generated files under src/api/ are derived from backend handlers, settings, and extension properties. The files in src/backend/router/ define the app's HTTP endpoints.
The initial app package contains sample handlers for global, project, and issue scopes. You can also add handlers for article and user scopes.
File-Based Routing
With file-based routing, the location and name of a backend handler file determine the endpoint that it provides. Instead of declaring endpoints manually in a separate configuration, you place each handler in a specific directory and name the file according to the supported HTTP method.
With Enhanced DX, backend handlers use the following path pattern:
Supported scopes are global, project, issue, article, and user. Route paths can be nested and may include hyphenated segments.
Handler Format
Every handler file exports the request type, response type, default handler, and a Handle alias for type generation.
Only types annotated with @zod-to-schema are picked up for generated API contracts and runtime validation.
Context Types
Each handler receives a context object that provides access to the request, response, current user, app settings, and scope-specific YouTrack entities.
The following TypeScript helper types define the context object for handlers with different HTTP methods:
Each context always includes ctx.currentUser, ctx.settings, ctx.request, and ctx.response. Scope-specific properties such as ctx.issue or ctx.project are available when the handler directory and generic scope match.
Permissions
To define which permissions are required to access a handler, use the withPermissions helper function from the Enhanced DX runtime package.
Add App Elements
The generated app includes the npm run generate command and its shorthand alias npm run g. Use these commands to add widgets, handlers, extension properties, and settings.
- Widget
Use the generator to add a widget for a selected extension point and update the app configuration automatically.
npm run g -- widget --key my-panel --extension-point ISSUE_BELOW_SUMMARY npm run g -- widget --key admin-page --extension-point MAIN_MENU_ITEM --name "Admin Page" npm run g -- widget --key project-tab --extension-point PROJECT_SETTINGS --permissions read-project- Handler
Use the generator to create backend handlers in the correct location and with the required type declarations.
npm run g -- handler global/health npm run g -- handler project/users --method POST npm run g -- h issue/comments --method POST --permissions read-issue,update-issue- Extension property
Use the generator to declare extension properties for YouTrack entities.
npm run g -- property Issue.customStatus npm run g -- property Issue.tags --type string --set npm run g -- p Article.rating --type integerAfter rebuilding the backend, generated extension properties are available through
ctx.issue.extensionProperties,ctx.project.extensionProperties, and related scoped entities.- App settings
Use the generator to initialize the settings schema and add properties to it.
npm run g -- settings init --title "My App Settings" --description "Admin configuration" npm run g -- settings add --name apiKey --type string --write-only npm run g -- settings add --name maxItems --type integer --min 1 --max 100
After you add or change backend elements, rebuild the backend or keep npm run dev running so generated files and uploaded app bundles stay up to date.
Use the Generated API Client
Frontend widgets can call backend handlers through a generated API client. This client is based on the handler files in src/backend/router/ and the request and response types declared in those files.
When you build the backend, the toolchain generates the ApiRouter type in src/api/api.d.ts. Widgets pass this type to the createApi helper function to get typed methods for each backend route.
The structure of the api object follows the file-based route structure. For example, a handler in src/backend/router/project/settings/GET.ts is available as api.project.settings.GET(...).
For project-scoped and issue-scoped handlers, include the corresponding entity ID in the request data. When the request contains projectId, the client routes the call through the project endpoint. When the request contains issueId, the client routes the call through the issue endpoint.
If a route is missing from the generated api object, rebuild the backend to refresh src/api/api.d.ts.
Update Entity Fields
Backend handlers can update values on YouTrack entities, such as issues and projects. The way you update a value depends on whether the value is an extension property declared by the app or a regular YouTrack field.
Use POST or PUT handlers for updates that persist changes in YouTrack. Mutations in GET or DELETE handlers can fail at runtime.
Use the following approaches when you need to persist field changes from a handler:
Field | Update method |
|---|---|
Extension properties declared by the app | Assign the value directly through |
Regular issue or project fields, including custom fields | Use the |
Here is an example that uses both approaches in an issue handler:
Troubleshooting
If the generated app package does not build, upload, or update in YouTrack as expected, use the following notes to check the most common setup and development issues.
Condition - The frontend build reports that it cannot find ./api/api.
Cause | Solution |
|---|---|
The API type definitions have not been generated yet. | Run |
Condition - Upload returns 401 Unauthorized.
Cause | Solution |
|---|---|
The upload command cannot authenticate with YouTrack. | Check the values in |
Condition - Changes are not uploading in watch mode.
Cause | Solution |
|---|---|
The changed file is outside the watched source directory, or the watcher has stopped responding. | Verify that the changed file is inside |
Condition - The frontend is blank in local development mode.
Cause | Solution |
|---|---|
The local development server is not running, or the frontend has a runtime error. | Make sure the local development server started on port 9000 and check the browser console for frontend errors. |
Condition - ts-to-zod failed or was skipped.
Cause | Solution |
|---|---|
The | Run |