Project structure
Understand the Rayfin scaffold layout, including rayfin.yml, deployment metadata, environment files, and the 1.36 universal app workspace.
Rayfin templates keep backend configuration, deployment state, and frontend code in predictable places. Flat templates and the 1.36 default blankapp template share root commands, but the default now creates the Universal App npm workspace.
Flat template layout
my-app/
├── rayfin/
│ ├── data/
│ │ ├── schema.ts
│ │ └── Todo.ts
│ ├── .env
│ ├── .project.json
│ ├── .deployments.json
│ ├── rayfin.yml
│ └── tsconfig.json
├── src/
├── package.json
├── tsconfig.json
└── README.mdUniversal App workspace
The CLI-facing blankapp template now creates the Universal App workspace. The hidden universal-app template name is still accepted, but users normally choose blankapp or the default prompt. The root owns orchestration scripts and rayfin/rayfin.yml; packages own runtime code.
my-app/
├── package.json
├── tsconfig.base.json
├── tsconfig.json
├── rayfin/
│ ├── .env
│ ├── .project.json
│ ├── .deployments.json
│ └── rayfin.yml
└── packages/
├── frontend/
├── data/
└── shared/| Package | Stable name | Owns |
|---|---|---|
packages/frontend | @rayfin-app/frontend | React, Vite, Fabric auth wiring, browser UI, and static output. |
packages/data | @rayfin-app/data | Entity registration and schema exports. |
packages/shared | @rayfin-app/shared | Types shared across browser, data, and Functions code. |
packages/functions | @rayfin-app/functions | Added only when the Functions capability pack is applied. |
Root scripts coordinate the workspace:
{
"workspaces": ["packages/*"],
"scripts": {
"dev": "rayfin dev",
"dev:frontend": "npm run -w @rayfin-app/frontend dev",
"build:fabric": "npm run -w @rayfin-app/shared build && npm run -w @rayfin-app/data build && npm run -w @rayfin-app/frontend build:fabric",
"rayfin:up": "rayfin up"
}
}rayfin/rayfin.yml
rayfin.yml is the checked-in service declaration that rayfin dev and rayfin up sync to Fabric.
id: universal-app
name: Universal App
version: 1.0.0
services:
auth:
enabled: true
fabric:
enabled: true
externalEntraExchange: true
allowedRedirectUris:
- http://localhost:5173
data:
enabled: false
path: packages/data
buildCommand: npm run build
staticHosting:
enabled: true
path: packages/frontend
folder: dist
buildCommand: npm run build:fabric
indexDocument: index.html
assetAccess: protected
embedded:
only: falseservices.staticHosting.assetAccess replaces the older anonymousAccess authoring shape. New in 1.35.1
Service configuration fields
| Field | Type | Description |
|---|---|---|
id | string | Project slug and default Fabric item name. |
name | string | Human-readable app name. |
version | string | Project version. |
services.auth.enabled | boolean | Enables Rayfin auth services. |
services.auth.fabric.enabled | boolean | Enables Microsoft Entra ID through Fabric SSO. |
services.auth.allowedRedirectUris | string[] | Origins allowed to complete auth callbacks and Fabric SSO handoffs. Keep the local dev origin and deployed hosting origins. |
services.data.enabled | boolean | Enables the data service. Fabric deployments use dialect: mssql. |
services.data.path | string | Data package directory for workspace layouts. |
services.data.buildCommand | string | Command run from the data service path before packaging. |
services.staticHosting.path | string | Frontend package directory for static hosting. |
services.staticHosting.folder | string | Built asset folder, usually dist. |
services.staticHosting.assetAccess | protected | public | Hosted asset access posture. New in 1.35.1 |
services.functions.enabled | boolean | Enables Rayfin Functions. |
services.functions.auth.type | application | Required for enabled Functions. Changed in 1.36 |
String values in rayfin.yml support ${VAR} and ${VAR:-default} interpolation from rayfin/.env and the shell environment. See Environment variables.
Generated and local files
| File | Purpose | Commit it |
|---|---|---|
rayfin/.env | RAYFIN_PUBLIC_*, local dev port, and interpolation values. | No |
.env.local | Framework-specific values generated from rayfin/.env; in a universal app it lives under packages/frontend. | No |
rayfin/.project.json | Scaffold lineage identifier used for telemetry correlation. | Usually yes |
rayfin/.deployments.json | Fabric workspace IDs, item IDs, item names, publishable keys, hosting URLs, and active deployment. | No |
rayfin/.temp/ | Generated backend artifacts. | No |
Data and TypeScript files
Flat templates keep entity classes under rayfin/data/ and register them in rayfin/data/schema.ts. Universal apps keep data code under packages/data, and services.data.path tells the CLI where to build it.
Rayfin decorators require an ES2022 or later target. Templates already configure TypeScript and Vite; do not enable emitDecoratorMetadata, and do not switch to @vitejs/plugin-react-swc.
rayfin/tsconfig.json and root tsconfig.json
The Rayfin CLI compiles decorated entity files as a TypeScript project. Flat templates include rayfin/tsconfig.json and a project reference from the root tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable", "ESNext.Decorators"],
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"],
"references": [{ "path": "./rayfin" }]
}Do not set emitDecoratorMetadata to true. It requires legacy decorators, which are incompatible with Rayfin's TC39 decorators.
Vite configuration
Templates set an ES2022 target in Vite so decorator syntax is parsed consistently:
import { rayfinLocalDev } from '@microsoft/rayfin-local-dev/vite';
import react from '@vitejs/plugin-react-swc';
import { defineConfig, loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), 'VITE_');
const port = env.VITE_PORT ? Number(env.VITE_PORT) : undefined;
return {
plugins: [react(), rayfinLocalDev()],
...(port ? { server: { port, strictPort: true } } : {}),
build: { target: 'es2022' },
esbuild: { target: 'es2022' },
optimizeDeps: {
esbuildOptions: { target: 'es2022' },
},
};
});The rayfinLocalDev() plugin is development-only. It serves local rayfin.config.json, proxies Rayfin backend routes, routes local Functions calls, and supports local automatic sign-in for protected static assets.
Frontend environment generation
rayfin dev, rayfin up, and rayfin env map RAYFIN_PUBLIC_* values from rayfin/.env into the frontend framework's .env.local. For Vite, the generated variables use the VITE_ prefix:
| Rayfin value | Vite value |
|---|---|
RAYFIN_PUBLIC_API_URL | VITE_RAYFIN_API_URL |
RAYFIN_PUBLIC_PUBLISHABLE_KEY | VITE_RAYFIN_PUBLISHABLE_KEY |
RAYFIN_PUBLIC_WORKSPACE_ID | VITE_FABRIC_WORKSPACE_ID |
RAYFIN_PUBLIC_ITEM_ID | VITE_FABRIC_ITEM_ID |
RAYFIN_PUBLIC_PORTAL_URL | VITE_FABRIC_PORTAL_URL |
RAYFIN_PUBLIC_FRONTEND_PORT | VITE_PORT |
RAYFIN_PUBLIC_FUNCTIONS_URL | VITE_RAYFIN_FUNCTIONS_URL |
In a workspace layout, the file is written under services.staticHosting.path, such as packages/frontend/.env.local.
rayfin/.temp
rayfin/.temp/ contains generated backend artifacts, including compiled entity metadata and Data API Builder configuration. If the backend appears stale, restart rayfin dev or run npx rayfin up so the CLI regenerates and reapplies the artifacts.
Inspect my Rayfin project's package.json, rayfin/rayfin.yml, rayfin/.env, rayfin/.deployments.json, and any npm workspaces. Tell me whether it is a flat template or the 1.36 universal app layout, identify the data and static-hosting service paths, and explain which files are committed versus generated or gitignored.Next
- Develop locally — how this layout runs with
rayfin dev. - Hosting — static hosting configuration and access posture.
- Deploying with rayfin up — deployment metadata and commands.