Skip to main content

Overview

Convex is a serverless backend platform that provides a real-time database and functions-as-a-service. The site uses Convex to handle post creation and storage.
Convex eliminates the need for traditional backend infrastructure by providing a fully-managed database and serverless functions.

What is Convex?

Convex is a serverless backend-as-a-service platform that offers:

Real-time Database

NoSQL database with automatic reactivity

Type-safe Functions

Full TypeScript support with runtime validation

Serverless Architecture

No servers to manage or scale

Built-in Validation

Schema validation using Convex’s value system

The createPost Mutation

The core functionality is implemented through the createPost mutation in post-db/convex/posts.ts:4-12:
post-db/convex/posts.ts
import { v } from "convex/values";
import { internalMutation } from "./_generated/server";

export const createPost = internalMutation({
  args: {
    content: v.string(),
  },
  handler: async (ctx, args) => {
    const id = await ctx.db.insert("posts", { content: args.content });
    return id;
  },
});

Code Breakdown

Imports

import { v } from "convex/values";
import { internalMutation } from "./_generated/server";
  • v provides runtime type validation for function arguments
  • internalMutation creates a mutation that can only be called from other Convex functions (not directly from the client)

Mutation Definition

export const createPost = internalMutation({
  args: {
    content: v.string(),
  },
  // ...
});
The mutation accepts a single parameter:
content
string
required
The text content of the post to be created
This is an internalMutation, meaning it can only be called from other Convex functions, not directly from the client. This provides an extra layer of security.

Handler Logic

handler: async (ctx, args) => {
  const id = await ctx.db.insert("posts", { content: args.content });
  return id;
}
The handler performs these steps:
1

Receive context and arguments

ctx provides database access, args contains the validated content string
2

Insert into database

Uses ctx.db.insert() to add a new document to the “posts” table
3

Return the ID

Returns the auto-generated document ID for the newly created post

Database Schema

The mutation inserts documents into the "posts" table with this structure:
{
  content: string  // The post content
}
Convex automatically adds system fields like _id (unique identifier) and _creationTime (timestamp) to every document.

Using the Mutation

Since this is an internal mutation, it must be called from another Convex function:

From Another Mutation

import { internalMutation } from "./_generated/server";
import { internal } from "./_generated/api";

export const createPostFromClient = internalMutation({
  args: {
    content: v.string(),
  },
  handler: async (ctx, args) => {
    // Call the internal mutation
    const postId = await ctx.runMutation(internal.posts.createPost, {
      content: args.content,
    });
    return postId;
  },
});

From a Query

import { query } from "./_generated/server";
import { internal } from "./_generated/api";

export const getAllPosts = query({
  handler: async (ctx) => {
    // Read from the posts table
    const posts = await ctx.db.query("posts").collect();
    return posts;
  },
});

Key Features

The v.string() validator ensures that content is always a string at runtime, catching type errors before they reach the database.
Using internalMutation instead of mutation means this function cannot be called directly from client code, providing an additional security layer.
Convex automatically generates unique IDs for each document, which are returned by the insert() method.
Full support for modern async patterns makes database operations clean and readable.

Error Handling

Convex automatically handles common errors:
  • Validation errors: If content is not a string, Convex returns a clear error message
  • Database errors: Connection issues and write failures are handled gracefully
  • Type errors: TypeScript catches type mismatches at compile time
For production applications, consider adding custom error handling and logging within the handler function.

Next Steps

Add Queries

Create queries to read posts from the database

Add Validation

Add more sophisticated validation with Convex validators

Public Mutations

Convert to a public mutation for client access

Convex Docs

Explore the full Convex documentation

Build docs developers (and LLMs) love