
A CRUD application is the smallest useful test of a frontend stack. It has list, create, read, update, and delete flows. It has forms, API calls, loading states, empty states, validation, optimistic updates, and error handling. If you can build a clean CRUD feature in Vue, you can build most product screens.
This guide uses Vue 3 concepts and keeps the architecture practical rather than theoretical.
The application shape
Use a simple resource such as projects, customers, tasks, or products. The UI needs five core screens or states:
- List all records.
- View one record.
- Create a record.
- Edit a record.
- Delete or archive a record.
In a real app, these screens usually share layout, tables, cards, forms, empty states, modals, and notification components. If you have Figma designs for these states, Codia can help generate the initial Vue components from the design and reduce the time spent recreating layout by hand.
Project structure
A small Vue CRUD feature can start with:
src/
components/
EntityForm.vue
EntityTable.vue
ConfirmDialog.vue
pages/
EntityListPage.vue
EntityCreatePage.vue
EntityEditPage.vue
EntityDetailPage.vue
services/
entityApi.ts
types/
entity.tsVue's component model is built around reusable UI pieces, and the official Vue component docs describe components as independent pieces that can be composed into a tree. Keep that model visible in your CRUD feature: pages coordinate data and routing, components handle reusable UI.
Define the data model
Start with a TypeScript interface:
export interface Project {
id: string
name: string
status: 'active' | 'paused' | 'archived'
owner: string
updatedAt: string
}Then define payloads separately:
export interface ProjectInput {
name: string
status: Project['status']
owner: string
}Separating server records from form input avoids accidental coupling. The API may return id and timestamps, but the create form should not ask the user for those values.
Build the API layer
Keep API calls outside components:
export async function listProjects(): Promise<Project[]> {
const response = await fetch('/api/projects')
if (!response.ok) throw new Error('Failed to load projects')
return response.json()
}Repeat the pattern for getProject, createProject, updateProject, and deleteProject. A central service makes it easier to add auth headers, retry behavior, request cancellation, and typed errors later.
Build the list screen
The list screen needs more than rows:
- Initial loading state.
- Empty state.
- Error state with retry.
- Search or filters if the dataset is large.
- Pagination or infinite loading if needed.
- Clear affordances for create, view, edit, and delete.
Do not hide all behavior inside the table component. Let the page own data loading and actions, then pass rows and callbacks into EntityTable.vue.
Build the form
Use one form component for create and edit. Pass initial values and submit behavior as props.
The form should handle:
- Required fields.
- Field-level errors.
- Server validation messages.
- Disabled submit while saving.
- Dirty state.
- Cancel behavior.
For complex forms, use a validation library. For simple CRUD, a small local validation function is often enough.
Delete carefully
Delete is where many CRUD demos are too casual. Production deletion needs a confirmation step and a recovery plan. Depending on your product, consider archive instead of hard delete.
At minimum:
- Show the item name in the confirmation dialog.
- Disable the action while deleting.
- Handle API failure.
- Refresh the list or remove the item locally after success.
- Show a notification or inline result.
Design-to-code workflow
If your CRUD screens exist in Figma, generate the first pass with Codia, then refactor:
- Convert the list, empty, form, and detail frames.
- Extract shared controls into components.
- Replace static rows with real data rendering.
- Add form state and validation.
- Wire the API service.
- Test all loading and failure states.
Generated UI speeds up structure, but the CRUD behavior is still engineering work.
FAQ
What is a CRUD app in Vue?
A CRUD app lets users create, read, update, and delete records through Vue components, routes, forms, and API calls.
Should Vue CRUD components call fetch directly?
Small demos can, but production apps should usually keep API calls in a service layer so components stay focused on UI behavior.
Can Codia help build a Vue CRUD app?
Yes. Codia can generate the UI starting point from Figma designs. Engineers still need to wire data, validation, routing, permissions, and errors.