page.tsx101 lines · main
1import type { Metadata } from 'next';
2import Link from 'next/link';
3
4import { BackgroundGrid } from '../../components/marketing/background-grid';
5import { SiteFooter } from '../../components/marketing/site-footer';
6import { SiteHeader } from '../../components/marketing/site-header';
7import { getSessionUser } from '../../lib/session';
8
9export const metadata: Metadata = {
10 title: 'compare — briven vs convex, supabase, firebase',
11 description:
12 'feature-by-feature comparison: briven vs convex, supabase, firebase. honest tradeoffs, not marketing.',
13};
14
15interface Comparison {
16 slug: string;
17 name: string;
18 oneline: string;
19 blurb: string;
20}
21
22const COMPARISONS: Comparison[] = [
23 {
24 slug: 'convex',
25 name: 'convex',
26 oneline: 'reactive backend with a closed proprietary database',
27 blurb:
28 'convex pioneered the reactive-queries pattern briven adopts. the difference is the floor: convex stores your data in its own engine; briven stores it in plain postgres, which means pg_dump moves your whole product anywhere.',
29 },
30 {
31 slug: 'supabase',
32 name: 'supabase',
33 oneline: 'postgres + auth + storage + row-level security',
34 blurb:
35 'both are postgres-first. supabase exposes the database directly through postgrest + row-level security; briven puts a typed function layer in front and adds convex-style reactive subscriptions that supabase doesn\'t have.',
36 },
37 {
38 slug: 'firebase',
39 name: 'firebase',
40 oneline: 'document store with client-side security rules',
41 blurb:
42 'firebase is nosql with realtime built-in; briven is real sql on postgres with realtime built-in. firebase rules run on the client query; briven runs typed functions on the server with project-scoped connections.',
43 },
44];
45
46export default async function CompareHubPage() {
47 const user = await getSessionUser().catch(() => null);
48 return (
49 <main className="relative min-h-dvh overflow-hidden bg-[var(--color-bg)] text-[var(--color-text)]">
50 <BackgroundGrid />
51 <SiteHeader user={user} />
52
53 <section className="relative z-10 mx-auto w-full max-w-4xl px-6 pb-12 pt-16 sm:pt-24">
54 <p className="font-mono uppercase tracking-[0.12em] text-[var(--color-primary)] text-[var(--text-xs)]">
55 compare
56 </p>
57 <h1 className="mt-4 font-sans font-medium leading-[1.05] tracking-[-0.03em] text-[var(--color-text)] text-[var(--text-display-3)] sm:text-[var(--text-display-2)]">
58 briven against the field.
59 </h1>
60 <p className="mt-6 max-w-2xl leading-[1.6] text-[var(--color-text-muted)] text-[var(--text-body)]">
61 honest comparisons against the platforms briven is most often weighed against. every row
62 is a real difference — not a checkbox we invented to favour ourselves. where the other
63 platform wins, we say so.
64 </p>
65 </section>
66
67 <section className="relative z-10 mx-auto w-full max-w-4xl px-6 pb-20">
68 <div className="grid grid-cols-1 gap-4 md:grid-cols-3">
69 {COMPARISONS.map((c) => (
70 <Link
71 key={c.slug}
72 href={`/compare/${c.slug}`}
73 className="group flex flex-col gap-3 rounded-[var(--radius-lg)] border border-[var(--color-border-subtle)] bg-[var(--color-surface)] p-6 transition hover:border-[var(--color-border-strong)]"
74 >
75 <p className="font-mono uppercase tracking-[0.12em] text-[var(--color-text-subtle)] text-[var(--text-xs)]">
76 vs
77 </p>
78 <h2 className="font-sans font-medium tracking-[-0.02em] text-[var(--color-text)] text-[var(--text-h3)]">
79 {c.name}
80 </h2>
81 <p className="font-mono text-xs text-[var(--color-text-muted)]">{c.oneline}</p>
82 <p className="mt-2 leading-[1.6] text-[var(--color-text-muted)] text-[var(--text-small)]">
83 {c.blurb}
84 </p>
85 <span className="mt-auto font-mono text-xs text-[var(--color-text-link)] group-hover:underline">
86 read the comparison →
87 </span>
88 </Link>
89 ))}
90 </div>
91
92 <p className="mt-10 font-mono text-xs text-[var(--color-text-subtle)]">
93 missing a comparison you want? open an issue on the repo or ask in the alpha discord. we
94 add a comparison page when at least three operators ask the same migration question.
95 </p>
96 </section>
97
98 <SiteFooter />
99 </main>
100 );
101}