DEV Community

Alex Spinov
Alex Spinov

Posted on

Convex Has a Free API That Makes Real-Time Apps Trivially Easy

Convex is a reactive backend-as-a-service that eliminates the gap between your database and your UI. Write queries and mutations in TypeScript — they run on the server but feel like local function calls.

Reactive Queries: Auto-Updating UI

// convex/products.ts (server)
import { query } from "./_generated/server";
import { v } from "convex/values";

export const list = query({
  args: { category: v.string() },
  handler: async (ctx, { category }) => {
    return await ctx.db
      .query("products")
      .withIndex("by_category", (q) => q.eq("category", category))
      .order("desc")
      .take(50);
  },
});

// React component — auto-updates when data changes!
import { useQuery } from "convex/react";
import { api } from "../convex/_generated/api";

function ProductList() {
  const products = useQuery(api.products.list, { category: "electronics" });
  // products automatically updates when ANY user adds/edits/deletes a product
  return products?.map(p => <ProductCard key={p._id} product={p} />);
}
Enter fullscreen mode Exit fullscreen mode

No WebSocket setup. No cache invalidation. No refetching. It just works.

Mutations: Type-Safe Writes

// convex/products.ts
import { mutation } from "./_generated/server";
import { v } from "convex/values";

export const add = mutation({
  args: {
    title: v.string(),
    price: v.number(),
    url: v.string(),
    category: v.string(),
  },
  handler: async (ctx, args) => {
    const id = await ctx.db.insert("products", {
      ...args,
      scrapedAt: Date.now(),
    });
    return id;
  },
});

// Client — fully typed
import { useMutation } from "convex/react";
const addProduct = useMutation(api.products.add);
await addProduct({ title: "Widget", price: 29.99, url: "...", category: "electronics" });
Enter fullscreen mode Exit fullscreen mode

Actions: External API Calls

import { action } from "./_generated/server";
import { v } from "convex/values";

export const scrapeAndStore = action({
  args: { url: v.string() },
  handler: async (ctx, { url }) => {
    // Call external scraping API
    const response = await fetch(`https://api.apify.com/v2/acts/...`);
    const data = await response.json();

    // Store results using mutations
    for (const item of data.items) {
      await ctx.runMutation(api.products.add, item);
    }
    return { count: data.items.length };
  },
});
Enter fullscreen mode Exit fullscreen mode

Scheduled Functions: Cron Jobs

// convex/crons.ts
import { cronJobs } from "convex/server";
import { api } from "./_generated/api";

const crons = cronJobs();

crons.interval("scrape prices", { hours: 1 }, api.scraping.scrapeAndStore, {
  url: "https://example.com/products"
});

crons.cron("daily report", "0 9 * * *", api.reports.generateDaily, {});

export default crons;
Enter fullscreen mode Exit fullscreen mode

File Storage API

// Upload
const uploadUrl = await generateUploadUrl();
await fetch(uploadUrl, { method: "POST", body: file });

// Store reference in document
await ctx.db.insert("exports", { fileId: storageId, format: "csv" });

// Get URL
const url = await ctx.storage.getUrl(fileId);
Enter fullscreen mode Exit fullscreen mode

Build real-time dashboards with scraped data? My Apify tools + Convex = live-updating data displays.

Custom real-time solution? Email spinov001@gmail.com

Top comments (0)