Complete Convex Complete Guide | Realtime Backend
이 글의 핵심
Complete guide to building realtime backend with Convex. From type-safe APIs, realtime subscriptions, file storage to authentication with practical exam...
Key Takeaways
Complete guide to building realtime backend with Convex. From type-safe APIs, realtime subscriptions, file storage to authentication with practical examples.
Real-World Experience: Sharing experience of switching from Firebase to Convex, improving type safety and making realtime features more powerful.
Introduction: “Realtime Backend Is Complex”
Real-World Problem Scenarios
Scenario 1: Lack of Type Safety
Firebase has weak typing. Convex provides perfect type safety.
Scenario 2: Difficult Realtime Subscriptions
WebSocket setup is complex. Convex handles it automatically.
Scenario 3: Need Backend Logic
Difficult to handle on client. Convex provides server functions.
1. What is Convex?
Core Features
Convex is a realtime backend platform. Key Advantages:
- Type Safety: End-to-End TypeScript
- Realtime: Automatic subscriptions
- Server Functions: Query, Mutation, Action
- File Storage: Built-in
- Authentication: Clerk integration
2. Project Setup
Installation
npm create convex@latest
Project Structure
Here’s an implementation example. Try running the code directly to see how it works.
my-convex-app/
├── convex/
│ ├── schema.ts
│ ├── users.ts
│ └── posts.ts
├── src/
│ └── app/
└── convex.json
3. Schema Definition
Here’s a detailed implementation using TypeScript. Import necessary modules. Please review the code to understand the role of each part.
// convex/schema.ts
import { defineSchema, defineTable } from 'convex/server';
import { v } from 'convex/values';
export default defineSchema({
users: defineTable({
email: v.string(),
name: v.string(),
createdAt: v.number(),
}).index('by_email', ['email']),
posts: defineTable({
title: v.string(),
content: v.string(),
authorId: v.id('users'),
published: v.boolean(),
createdAt: v.number(),
})
.index('by_author', ['authorId'])
.index('by_published', ['published']),
});
4. Query & Mutation
Query
Here’s a detailed implementation using TypeScript. Import necessary modules, perform tasks efficiently with async processing. Please review the code to understand the role of each part.
// convex/posts.ts
import { query } from './_generated/server';
import { v } from 'convex/values';
export const list = query({
args: {},
handler: async (ctx) => {
return await ctx.db.query('posts').collect();
},
});
export const get = query({
args: { id: v.id('posts') },
handler: async (ctx, args) => {
return await ctx.db.get(args.id);
},
});
Mutation
Here’s a detailed implementation using TypeScript. Import necessary modules, perform tasks efficiently with async processing. Please review the code to understand the role of each part.
import { mutation } from './_generated/server';
import { v } from 'convex/values';
export const create = mutation({
args: {
title: v.string(),
content: v.string(),
authorId: v.id('users'),
},
handler: async (ctx, args) => {
const postId = await ctx.db.insert('posts', {
...args,
published: false,
createdAt: Date.now(),
});
return postId;
},
});
export const update = mutation({
args: {
id: v.id('posts'),
title: v.string(),
},
handler: async (ctx, args) => {
await ctx.db.patch(args.id, { title: args.title });
},
});
5. React Integration
Provider
Here’s an implementation example using TypeScript. Import necessary modules. Please review the code to understand the role of each part.
// app/ConvexClientProvider.tsx
'use client';
import { ConvexProvider, ConvexReactClient } from 'convex/react';
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
export default function ConvexClientProvider({ children }) {
return <ConvexProvider client={convex}>{children}</ConvexProvider>;
}
useQuery
Here’s a detailed implementation using TypeScript. Import necessary modules, process data with loops, perform branching with conditionals. Please review the code to understand the role of each part.
'use client';
import { useQuery } from 'convex/react';
import { api } from '../convex/_generated/api';
export default function Posts() {
const posts = useQuery(api.posts.list);
if (posts === undefined) return <div>Loading...</div>;
return (
<ul>
{posts.map((post) => (
<li key={post._id}>{post.title}</li>
))}
</ul>
);
}
useMutation
Here’s a detailed implementation using TypeScript. Import necessary modules, perform tasks efficiently with async processing. Please review the code to understand the role of each part.
'use client';
import { useMutation } from 'convex/react';
import { api } from '../convex/_generated/api';
export default function CreatePost() {
const createPost = useMutation(api.posts.create);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
await createPost({
title: formData.get('title') as string,
content: formData.get('content') as string,
authorId: 'user-id',
});
};
return (
<form onSubmit={handleSubmit}>
<input name="title" required />
<textarea name="content" />
<button type="submit">Create Post</button>
</form>
);
}
6. Action (External API)
Here’s a detailed implementation using TypeScript. Import necessary modules, perform tasks efficiently with async processing. Please review the code to understand the role of each part.
// convex/actions.ts
import { action } from './_generated/server';
import { v } from 'convex/values';
export const sendEmail = action({
args: {
to: v.string(),
subject: v.string(),
body: v.string(),
},
handler: async (ctx, args) => {
const response = await fetch('https://api.sendgrid.com/v3/mail/send', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SENDGRID_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
personalizations: [{ to: [{ email: args.to }] }],
from: { email: '[email protected]' },
subject: args.subject,
content: [{ type: 'text/plain', value: args.body }],
}),
});
return response.ok;
},
});
7. File Storage
Here’s a detailed implementation using TypeScript. Import necessary modules, perform tasks efficiently with async processing. Please review the code to understand the role of each part.
// convex/files.ts
import { mutation } from './_generated/server';
export const generateUploadUrl = mutation({
args: {},
handler: async (ctx) => {
return await ctx.storage.generateUploadUrl();
},
});
export const saveFile = mutation({
args: { storageId: v.string() },
handler: async (ctx, args) => {
await ctx.db.insert('files', {
storageId: args.storageId,
createdAt: Date.now(),
});
},
});
// Client
const generateUploadUrl = useMutation(api.files.generateUploadUrl);
const saveFile = useMutation(api.files.saveFile);
const handleUpload = async (file: File) => {
const uploadUrl = await generateUploadUrl();
const response = await fetch(uploadUrl, {
method: 'POST',
body: file,
});
const { storageId } = await response.json();
await saveFile({ storageId });
};
Summary and Checklist
Key Summary
- Convex: Realtime backend
- Type Safety: End-to-End TypeScript
- Realtime: Automatic subscriptions
- Server Functions: Query, Mutation, Action
- File Storage: Built-in
- Authentication: Clerk integration
Implementation Checklist
- Create Convex project
- Define schema
- Implement queries
- Implement mutations
- Integrate React
- Implement actions
- Implement file storage
Related Articles
- Complete Supabase Guide
- Complete tRPC Guide
- Complete Firebase Guide
Keywords Covered
Convex, Backend, Realtime, TypeScript, React, Serverless, Database
Frequently Asked Questions (FAQ)
Q. How does it compare to Firebase?
A. Convex has much better type safety. Firebase is more mature with more features.
Q. How does it compare to Supabase?
A. Convex has more powerful realtime features. Supabase is PostgreSQL-based and more flexible.
Q. Can I use it for free?
A. Yes, there’s a free plan. Free up to 1GB data and 1GB file storage.
Q. Is it safe to use in production?
A. Yes, many startups are using it.
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Complete guide to building realtime backend with Convex. From type-safe APIs, realtime subscriptions, file storage to au… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- Supabase 가이드 — Firebase 대체 오픈소스 BaaS, Postgres + Auth +
- tRPC 가이드 — End-to-end 타입 안전 API, REST·GraphQL 없이 TypeScript만
이 글에서 다루는 키워드 (관련 검색어)
Convex, Backend, Realtime, TypeScript, React, Serverless, Database 등으로 검색하시면 이 글이 도움이 됩니다.