Project Structure
Understand the full-stack TypeScript architecture of deco applications
Deco CMS apps are full-stack TypeScript monorepos. Backend (MCP server) and frontend (React app) share types, deploy together, and communicate via typed RPC, no REST APIs needed.
One codebase, one deploy: Backend changes instantly available in frontend with full type safety.
Directory Structure
my-ai-app/
βββ package.json # Root workspace scripts (dev, gen, deploy)
βββ tsconfig.json # Shared TypeScript configuration
β
βββ server/ # Backend: MCP Server (Cloudflare Worker)
β βββ main.ts # Server entry point
β βββ deco.gen.ts # Auto-generated types (never edit)
β β
β βββ tools/ # Tool definitions by domain
β β βββ index.ts # Central export for all tools
β β βββ todos.ts # Example: Todo CRUD tools
β β βββ user.ts # Example: User management tools
β β
β βββ schema.ts # Database schema (Drizzle ORM + SQLite)
β βββ db.ts # Database connection helper
β βββ drizzle.config.ts # Drizzle configuration
β βββ drizzle/ # Database migration files
β βββ wrangler.toml # Cloudflare Workers config
β
βββ view/ # Frontend: React App (Vite + TanStack Router)
βββ src/
β βββ main.tsx # App entry point with router
β β
β βββ routes/ # Page components (TanStack Router)
β β βββ home.tsx # Example: Homepage route
β β
β βββ components/ # Reusable UI components
β β βββ ui/ # shadcn/ui design system
β β βββ ... # Custom components
β β
β βββ hooks/ # Custom React hooks
β β βββ useToolCalls.ts # Example: Tool call wrapper
β β
β βββ lib/ # Core utilities
β β βββ rpc.ts # Typed RPC client (calls backend)
β β βββ utils.ts # General utilities
β β
β βββ styles.css # Tailwind CSS styles
β
βββ public/ # Static assets (images, fonts)
βββ vite.config.ts # Vite bundler configuration
βββ components.json # shadcn/ui configuration
βββ package.json # Frontend dependencies
Development Flow
- Define tool in
server/tools/ - Run
npm run gen:selfto generate types - Call
client.tools.YOUR_TOOL(...)from React - TypeScript enforces correctness at compile time
No REST APIs, no version mismatches, no integration code.
Backend ( /server )
Your Cloudflare Worker serves:
/mcp- MCP server for AI agents/rpc- Typed RPC for your React UI/- Static assets (built React app)
main.ts
import { withRuntime } from "@deco/workers-runtime";
import { StateSchema } from "./deco.gen.ts";
import { tools } from "./tools/";
import { workflows } from "./workflows/";
import { views } from "./views";
const runtime = withRuntime<Env, typeof StateSchema>({
oauth: {
scopes: ["AI_GENERATE", "AI_GENERATE_OBJECT"],
state: StateSchema,
},
tools,
workflows,
views,
fetch: fallbackToView("/"), // Serves React assets
});
export const Workflow = runtime.Workflow;
export default runtime;
OAuth Scopes: Request permissions for AI generation capabilities.
State Schema: Configuration form users fill when installing your app. Extend with custom fields for API keys, environment settings, etc.
tools/
Organize tools by domain:
tools/
βββ index.ts # Export all tools
βββ customers.ts # Customer-related tools
βββ billing.ts # Billing-related tools
// tools/index.ts
export { customerTools } from "./customers";
export { billingTools } from "./billing";
export const tools = [
...customerTools,
...billingTools,
];
See Building Tools for details.
workflows/
Organize workflows by domain:
// workflows/index.ts
export const workflows = [
// Add workflow creators here
];
views.ts
External React apps that integrate with your MCP:
export const views = () => [
{
title: "My App",
icon: "dashboard",
url: "https://my-app.deco.page",
},
];
deco.gen.ts
Auto-generated types. Never edit manually.
npm run gen # Regenerate after adding integrations
npm run gen:self # Generate types for your tools
schema.ts and db.ts
Database schema (Drizzle ORM + SQLite):
// schema.ts
export const customers = sqliteTable("customers", {
id: integer("id").primaryKey(),
name: text("name"),
email: text("email"),
});
// db.ts
export const getDb = (env: Env) => getDatabase(env, schema);
wrangler.toml
Cloudflare Workers configuration. Auto-updated when adding integrations.
Frontend ( /view )
React 19 + Tailwind v4 + TanStack Router.
view/src/
βββ main.tsx # Entry point
βββ routes/ # Pages
βββ components/ui/ # UI components
βββ lib/rpc.ts # Typed RPC client
βββ styles.css # Tailwind styles
RPC Client
The rpc.ts client is auto-generated from your backend tools:
// view/src/lib/rpc.ts
import { createClient } from "@deco/workers-runtime/client";
import type { Env } from "../../server/deco.gen.ts";
export const client = createClient<Env["SELF"]>();
Usage in React:
import { client } from "./lib/rpc";
const result = await client.tools.EMAIL_SEND({
to: "user@example.com",
subject: "Welcome",
body: "Thanks for signing up",
});
TypeScript provides autocomplete and type checking for all tool inputs/outputs.
See Building Views for details.
Found an error or want to improve this page?
Edit this page