Code Mirror analyzes existing frontend or backend code and generates the corresponding counterpart on the other side. It understands the structural semantics — API contracts, data models, routing, validation, state management — and produces idiomatic, production-ready code that perfectly mirrors the source.
Activate Code Mirror when the user:
First, understand what the user has and what they want.
Source side detection (read the code the user provides):
CluesSideuseState, useEffect, useCallback, axios, fetch, onClick, ref, component, template, v-for, v-if, ngIf, ngFor, queryClient, useQuery, useMutation, .tsx, .jsx, .vue, .svelteFrontend@app.route, router., req.body, res.json, @Controller, @GetMapping, @PostMapping, @RestController, Model.find, Schema, prisma, entity, repository, BaseModel, Depends, HTTPException, .go, .java, .py with fastapi/ djangoBackend
If ambiguous, ask: "Is this frontend or backend code? What framework are you using?"
Target stack detection (infer from existing project or ask the user):
Check the user's project files in the workspace:
FileStackpackage.jsonCheck dependencies for React, Vue, Angular, Express, NestJSrequirements.txt / pyproject.tomlPython with FastAPI, Django, Flaskgo.modGo with Gin, Echo, net/httppom.xml / build.gradleJava with Spring BootCargo.tomlRust with Actix, Rocket*.csprojC# with ASP.NET Core
If no existing project, ask: "What stack do you want me to generate for? (e.g., Express + TypeScript, FastAPI, Go Gin, Spring Boot)"
Read and deeply understand the source code. Extract the following based on side:
1. API Calls — all endpoints the frontend hits
typescript
// For each API call, record:
// - HTTP method (GET, POST, PUT, PATCH, DELETE)
// - URL path (/api/users, /api/users/:id)
// - Request body shape (from the data being sent)
// - Response shape (from how the response is used)
// - Query parameters (from URL params)
// - Path parameters (from template strings like `/users/${id}`)
axios.get('/api/users') // GET /api/users → User[]
axios.post('/api/users', { name, email }) // POST /api/users → User
axios.put(`/api/users/${id}`, { name }) // PUT /api/users/:id → User
axios.delete(`/api/users/${id}`) // DELETE /api/users/:id
fetch('/api/users?page=1&limit=20') // GET with query params
2. Data Models — TypeScript interfaces, PropTypes, Zod schemas
typescript
// Extract: name, all fields, field types, optional/required markers, enums, default values
interface User {
id: string; // required string
name: string; // required string
email: string; // required string
role: 'admin' | 'user'; // enum
age?: number; // optional number
createdAt: Date; // date
}
3. Form Validation Rules — Zod, Yup, or manual validation
typescript
// Extract: field name, validation type (required, email, min, max, pattern, custom)
const schema = z.object({
name: z.string().min(2).max(50),
email: z.string().email(),
age: z.number().min(18).optional(),
password: z.string().min(8),
});
4. State Management Patterns (optional, for complex apps)
typescript
// Extract: store structure, state shape, actions that modify state
const useUserStore = create((set) => ({
users: [],
loading: false,
error: null,
fetchUsers: async () => { ... },
addUser: (user) => set((state) => ({ users: [...state.users, user] })),
}));
1. Route Definitions — every endpoint the backend exposes
python
# For each route, record:
# - Path (including path parameters like /users/{user_id})
# - HTTP method
# - Request body schema (from Pydantic model or DTO)
# - Query parameters (from function arguments)
# - Response model (from response_model or return type)
# - Status codes (especially 201, 204)
@router.get("/users") # GET /users → List[UserOut]
@router.get("/users/{user_id}") # GET /users/:id → UserOut
@router.post("/users") # POST /users → UserOut
@router.put("/users/{user_id}") # PUT /users/:id → UserOut
@router.delete("/users/{user_id}", status_code=204) # DELETE /users/:id → 204
2. Data Models / Schemas — database models and API schemas
python
# Extract: name, fields, types, required/optional, validators, relationships
class User(BaseModel):
id: str
name: str = Field(..., min_length=1, max_length=100)
email: EmailStr
role: Literal["admin", "user"] = "user"
age: Optional[int] = Field(None, ge=0, le=120)
created_at: datetime
3. Business Logic (for more complete generation)
python
# Extract: operations, side effects (email sending, logging), error handling patterns
def create_user(db: Session, user: UserCreate):
# hash password
# check if email exists
# send welcome email
# return created user
pass
4. Authentication/Authorization
python
# Extract: auth method (JWT, session, API key), protected routes, role requirements
@router.get("/admin/users", dependencies=[Depends(require_admin)])
async def get_admin_users(...):
pass
Generate code following the target stack's best practices. Always produce code that fits naturally into the existing project structure.
After generation, verify consistency and present the code clearly.
Consistency Checklist:
// TODO: implementOutput Format:
For each generated file, show:
Example:
text
I'll generate the Express backend for your React todo form.
`src/models/Todo.ts`
```typescript
// full file content
src/validators/todoValidator.ts
typescript
// full file content
src/routes/todos.ts
typescript
// full file content
POST /api/todos expects { title, description } and returns a todo with an id. All validation rules from your frontend form are mirrored in the backend Zod schema.#Model (Mongoose):
typescript
import mongoose, { Schema, Document } from 'mongoose';
export interface I{{Resource}} extends Document {
{{#each fields}}
{{name}}: {{mongooseType}};
{{/each}}
createdAt: Date;
updatedAt: Date;
}
const {{resource}}Schema = new Schema<I{{Resource}}>(
{
{{#each fields}}
{{name}}: {
type: {{mongooseType}},
required: {{required}}{{#if unique}}, unique: true{{/if}}
},
{{/each}}
},
{ timestamps: true }
);
export const {{Resource}}Model = mongoose.model<I{{Resource}}>('{{Resource}}', {{resource}}Schema);
Validator (Zod):
typescript
import { z } from 'zod';
export const create{{Resource}}Schema = z.object({
{{#each fields}}
{{name}}: z.{{zodType}}(){{#if required}}{{else}}.optional(){{/if}}{{#if validation}}.{{validation}}{{/if}},
{{/each}}
});
export const update{{Resource}}Schema = create{{Resource}}Schema.partial();
export type Create{{Resource}}Input = z.infer<typeof create{{Resource}}Schema>;
export type Update{{Resource}}Input = z.infer<typeof update{{Resource}}Schema>;
Route:
typescript
import { Router } from 'express';
import { {{Resource}}Model } from '../models/{{Resource}}';
import { validate } from '../middleware/validate';
import { create{{Resource}}Schema, update{{Resource}}Schema } from '../validators/{{resource}}Validator';
import { authMiddleware } from '../middleware/auth';
const router = Router();
// Apply auth middleware to all routes (if needed)
router.use(authMiddleware);
router.get('/', async (req, res) => {
const items = await {{Resource}}Model.find();
res.json(items);
});
router.get('/:id', async (req, res) => {
const item = await {{Resource}}Model.findById(req.params.id);
if (!item) return res.status(404).json({ error: '{{Resource}} not found' });
res.json(item);
});
router.post('/', validate(create{{Resource}}Schema), async (req, res) => {
const item = await {{Resource}}Model.create(req.body);
res.status(201).json(item);
});
router.put('/:id', validate(update{{Resource}}Schema), async (req, res) => {
const item = await {{Resource}}Model.findByIdAndUpdate(req.params.id, req.body, { new: true });
if (!item) return res.status(404).json({ error: '{{Resource}} not found' });
res.json(item);
});
router.delete('/:id', async (req, res) => {
const item = await {{Resource}}Model.findByIdAndDelete(req.params.id);
if (!item) return res.status(404).json({ error: '{{Resource}} not found' });
res.status(204).end();
});
export default router;
Schema (Pydantic):
python
from pydantic import BaseModel, Field, EmailStr
from typing import Optional
from datetime import datetime
from enum import Enum
class {{Resource}}Role(str, Enum):
{{#each enums}}
{{value}} = "{{value}}"
{{/each}}
class {{Resource}}Base(BaseModel):
{{#each fields}}
{{name}}: {{pythonType}} = Field(
{{#if required}}...{{else}}None{{/if}},
{{#if validation}}...{{/if}}
)
{{/each}}
class {{Resource}}Create({{Resource}}Base):
{{#each requiredFields}}
{{name}}: {{pythonType}}
{{/each}}
class {{Resource}}Update(BaseModel):
{{#each fields}}
{{name}}: Optional[{{pythonType}}] = None
{{/each}}
class {{Resource}}Out({{Resource}}Base):
id: str
created_at: datetime
updated_at: Optional[datetime] = None
class Config:
from_attributes = True
Router:
python
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import List
from app.database import get_db
from app.schemas.{{resource}} import {{Resource}}Create, {{Resource}}Update, {{Resource}}Out
from app import crud
router = APIRouter(prefix="/{{resource}}s", tags=["{{resource}}s"])
@router.get("", response_model=List[{{Resource}}Out])
async def list_{{resource}}s(
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=100),
db: Session = Depends(get_db),
):
return crud.{{resource}}.get_multi(db, skip=skip, limit=limit)
@router.get("/{{item_id}}", response_model={{Resource}}Out)
async def get_{{resource}}({{item_id}}: str, db: Session = Depends(get_db)):
item = crud.{{resource}}.get(db, id={{item_id}})
if not item:
raise HTTPException(status_code=404, detail="{{Resource}} not found")
return item
@router.post("", response_model={{Resource}}Out, status_code=201)
async def create_{{resource}}(
item: {{Resource}}Create,
db: Session = Depends(get_db),
):
return crud.{{resource}}.create(db, obj_in=item)
@router.put("/{{item_id}}", response_model={{Resource}}Out)
async def update_{{resource}}(
{{item_id}}: str,
item: {{Resource}}Update,
db: Session = Depends(get_db),
):
db_item = crud.{{resource}}.get(db, id={{item_id}})
if not db_item:
raise HTTPException(status_code=404, detail="{{Resource}} not found")
return crud.{{resource}}.update(db, db_obj=db_item, obj_in=item)
@router.delete("/{{item_id}}", status_code=204)
async def delete_{{resource}}({{item_id}}: str, db: Session = Depends(get_db)):
item = crud.{{resource}}.get(db, id={{item_id}})
if not item:
raise HTTPException(status_code=404, detail="{{Resource}} not found")
crud.{{resource}}.remove(db, id={{item_id}})
Types:
typescript
// types/{{resource}}.ts
export interface {{Resource}} {
id: string;
{{#each fields}}
{{name}}: {{tsType}};
{{/each}}
createdAt: string;
updatedAt: string;
}
export interface Create{{Resource}}Input {
{{#each requiredFields}}
{{name}}: {{tsType}};
{{/each}}
{{#each optionalFields}}
{{name}}?: {{tsType}};
{{/each}}
}
export interface Update{{Resource}}Input {
{{#each fields}}
{{name}}?: {{tsType}};
{{/each}}
}
API Client:
typescript
// api/{{resource}}.ts
import axios from 'axios';
import type { {{Resource}}, Create{{Resource}}Input, Update{{Resource}}Input } from '../types/{{resource}}';
const BASE_URL = '/api/{{resource}}s';
export const {{resource}}Api = {
list: () => axios.get<{{Resource}}[]>(BASE_URL),
getById: (id: string) => axios.get<{{Resource}}>(`${BASE_URL}/${id}`),
create: (data: Create{{Resource}}Input) => axios.post<{{Resource}}>(BASE_URL, data),
update: (id: string, data: Update{{Resource}}Input) =>
axios.put<{{Resource}}>(`${BASE_URL}/${id}`, data),
delete: (id: string) => axios.delete(`${BASE_URL}/${id}`),
};
React Query Hooks:
typescript
// hooks/use{{Resource}}s.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { {{resource}}Api } from '../api/{{resource}}';
import type { Create{{Resource}}Input, Update{{Resource}}Input } from '../types/{{resource}}';
export function use{{Resource}}s() {
return useQuery({
queryKey: ['{{resource}}s'],
queryFn: async () => {
const { data } = await {{resource}}Api.list();
return data;
},
});
}
export function use{{Resource}}(id: string) {
return useQuery({
queryKey: ['{{resource}}s', id],
queryFn: async () => {
const { data } = await {{resource}}Api.getById(id);
return data;
},
enabled: !!id,
});
}
export function useCreate{{Resource}}() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (input: Create{{Resource}}Input) => {{resource}}Api.create(input),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['{{resource}}s'] });
},
});
}
export function useUpdate{{Resource}}() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, ...input }: Update{{Resource}}Input & { id: string }) =>
{{resource}}Api.update(id, input),
onSuccess: (_, { id }) => {
queryClient.invalidateQueries({ queryKey: ['{{resource}}s'] });
queryClient.invalidateQueries({ queryKey: ['{{resource}}s', id] });
},
});
}
export function useDelete{{Resource}}() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => {{resource}}Api.delete(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['{{resource}}s'] });
},
});
}
Composable:
typescript
// composables/use{{Resource}}s.ts
import { ref, readonly } from 'vue';
import axios from 'axios';
import type { {{Resource}}, Create{{Resource}}Input, Update{{Resource}}Input } from '../types/{{resource}}';
export function use{{Resource}}s() {
const items = ref<{{Resource}}[]>([]);
const loading = ref(false);
const error = ref<string | null>(null);
const currentItem = ref<{{Resource}} | null>(null);
const fetchAll = async () => {
loading.value = true;
error.value = null;
try {
const { data } = await axios.get<{{Resource}}[]>('/api/{{resource}}s');
items.value = data;
} catch (e) {
error.value = (e as Error).message;
} finally {
loading.value = false;
}
};
const fetchOne = async (id: string) => {
loading.value = true;
error.value = null;
try {
const { data } = await axios.get<{{Resource}}>(`/api/{{resource}}s/${id}`);
currentItem.value = data;
return data;
} catch (e) {
error.value = (e as Error).message;
throw e;
} finally {
loading.value = false;
}
};
const create = async (input: Create{{Resource}}Input) => {
const { data } = await axios.post<{{Resource}}>('/api/{{resource}}s', input);
items.value.push(data);
return data;
};
const update = async (id: string, input: Update{{Resource}}Input) => {
const { data } = await axios.put<{{Resource}}>(`/api/{{resource}}s/${id}`, input);
const index = items.value.findIndex(i => i.id === id);
if (index !== -1) items.value[index] = data;
if (currentItem.value?.id === id) currentItem.value = data;
return data;
};
const remove = async (id: string) => {
await axios.delete(`/api/{{resource}}s/${id}`);
items.value = items.value.filter(i => i.id !== id);
if (currentItem.value?.id === id) currentItem.value = null;
};
return {
items: readonly(items),
currentItem: readonly(currentItem),
loading: readonly(loading),
error: readonly(error),
fetchAll,
fetchOne,
create,
update,
remove,
};
}
User says: "My FastAPI backend added a phone field to User. Update my React frontend."
Process:
phone fieldphone: string to User interfacephone to CreateUserInput/UpdateUserInputOutput format for sync:
I found the new phone field in your backend User model. Here are the frontend updates needed:
src/types/user.ts — add phone field:
diff
export interface User {
id: string;
name: string;
email: string;
+ phone: string;
role: 'admin' | 'user';
createdAt: string;
}
src/api/users.ts — no change needed (API calls remain the same)
src/components/UserForm.tsx — add phone input:
diff
const schema = z.object({
name: z.string().min(1),
email: z.string().email(),
+ phone: z.string().regex(/^\+?[1-9]\d{1,14}$/),
});
User says: "Here's my React form for creating a product. Generate the Express backend."
Process:
POST /api/productsname, price, descriptionname required, price positive numberUser says: "I need a todo app with users. Generate React frontend and Express backend."
Process:
id, name, email, password (hashed)id, title, completed, userId, createdAtWhen converting between languages, use these mappings:
TypeScriptPython (Pydantic)string``str``number``int | float``boolean``bool``Date / string (ISO)datetime``Array<T> | T[]``List[T]``Record<string, T>``Dict[str, T]``T | null | T | undefined``Optional[T]``interface``BaseModel``enum``Enum or Literal``'a' | 'b'``Literal['a', 'b']``Partial<T>Separate Update model (all optional)Omit<T, 'id'>Separate Create model without id
TypeScriptGostring``string``number``int | int64 | float64``boolean``bool``Date``time.Time``Array<T> | T[]``[]T``Record<string, T>``map[string]T``T | null``*T (pointer)interface``struct with JSON tagsenum``const with iota or string constants
TypeScriptJavastring``String``number``int | Long | Double``boolean``boolean | Boolean``Date``LocalDateTime | Instant``Array<T> | T[]``List<T>``Record<string, T>``Map<String, T>``T | null``Optional<T> or @Nullable``interfaceDTO class with getters/settersenum``enum
TypeScriptC#string``string``number``int | long | double | decimal``boolean``bool``Date``DateTime | DateTimeOffset``Array<T> | T[]``List<T> | T[]``Record<string, T>``Dictionary<string, T>``T | null``T? (nullable reference types)interface``class with properties
User:
Here's my React component for user management. Generate the Express backend for it.
tsx
interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'user';
}
function UserList() {
const [users, setUsers] = useState<User[]>([]);
useEffect(() => {
axios.get('/api/users').then(res => setUsers(res.data));
}, []);
const addUser = async (name: string, email: string, role: string) => {
const res = await axios.post('/api/users', { name, email, role });
setUsers([...users, res.data]);
};
const deleteUser = async (id: number) => {
await axios.delete(`/api/users/${id}`);
setUsers(users.filter(u => u.id !== id));
};
// ... render
}
Code Mirror response:
I'll generate the Express backend that mirrors your React frontend.
From your frontend, I identified:
src/models/User.ts
typescript
import mongoose, { Schema, Document } from 'mongoose';
export interface IUser extends Document {
name: string;
email: string;
role: 'admin' | 'user';
createdAt: Date;
updatedAt: Date;
}
const UserSchema = new Schema<IUser>(
{
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
role: { type: String, enum: ['admin', 'user'], default: 'user' },
},
{ timestamps: true }
);
export const UserModel = mongoose.model<IUser>('User', UserSchema);
src/validators/userValidator.ts
typescript
import { z } from 'zod';
export const createUserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
role: z.enum(['admin', 'user']).default('user'),
});
export const updateUserSchema = createUserSchema.partial();
src/routes/users.ts
typescript
import { Router } from 'express';
import { UserModel } from '../models/User';
import { validate } from '../middleware/validate';
import { createUserSchema, updateUserSchema } from '../validators/userValidator';
const router = Router();
router.get('/', async (req, res) => {
const users = await UserModel.find();
res.json(users);
});
router.post('/', validate(createUserSchema), async (req, res) => {
const user = await UserModel.create(req.body);
res.status(201).json(user);
});
router.delete('/:id', async (req, res) => {
const user = await UserModel.findByIdAndDelete(req.params.id);
if (!user) return res.status(404).json({ error: 'User not found' });
res.status(204).end();
});
export default router;
The routes exactly match your frontend calls. The POST validator enforces the same required fields your frontend sends.
text
### Example 2: Backend → Frontend (Sync Mode)
**User:**
My FastAPI backend User model added a phone field. Update my React frontend types and form.
Backend model:
python
class User(BaseModel):
id: str
name: str
email: str
phone: str = Field(..., pattern=r'^\+?[1-9]\d{1,14}$')
role: Literal['admin', 'user'] = 'user'
created_at: datetime
text
**Code Mirror response:**
I found the new phone field. Here are the frontend updates:
src/types/user.ts — add phone field:
diff
export interface User {
id: string;
name: string;
email: string;
+ phone: string;
role: 'admin' | 'user';
createdAt: string;
}
export interface CreateUserInput {
name: string;
email: string;
+ phone: string;
role?: 'admin' | 'user';
}
src/components/UserForm.tsx — add phone field with validation:
diff
const schema = z.object({
name: z.string().min(1),
email: z.string().email(),
+ phone: z.string().regex(/^\+?[1-9]\d{1,14}$/, 'Invalid phone number'),
role: z.enum(['admin', 'user']).optional(),
});
src/api/users.ts — no change needed (API calls remain the same, phone will be included automatically in POST/PUT)
Field(pattern=...) constraint.#Before finalizing generated code, verify:
// TODO: implement thisAlways include proper error handling appropriate to the stack:
typescript
// Express - 404
if (!item) return res.status(404).json({ error: 'Resource not found' });
// Express - validation
if (!result.success) return res.status(400).json({ errors: result.error.flatten() });
// Express - duplicate
try {
await Model.create(data);
} catch (err) {
if (err.code === 11000) return res.status(409).json({ error: 'Duplicate key' });
throw err;
}
python
# FastAPI - 404
if not item:
raise HTTPException(status_code=404, detail="Resource not found")
# FastAPI - validation (handled automatically by Pydantic)
# FastAPI - duplicate
if existing:
raise HTTPException(status_code=409, detail="Email already registered")
typescript
// React Query - errors are automatically available in query result
const { error } = useQuery(...);
// Axios interceptor for global error handling
axios.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// redirect to login
}
return Promise.reject(error);
}
);
When using this skill: