Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { EnumeratedType } from 'data/enumerated-types/enumerated-types-query'
import { noop } from 'lodash'
import {
Calendar,
Expand All @@ -11,8 +12,6 @@ import {
} from 'lucide-react'
import Link from 'next/link'
import { ReactNode, useState } from 'react'

import type { EnumeratedType } from 'data/enumerated-types/enumerated-types-query'
import {
AlertDescription_Shadcn_,
AlertTitle_Shadcn_,
Expand All @@ -36,6 +35,7 @@ import {
TooltipTrigger,
cn,
} from 'ui'

import {
POSTGRES_DATA_TYPES,
POSTGRES_DATA_TYPE_OPTIONS,
Expand Down Expand Up @@ -165,7 +165,7 @@ const ColumnType = ({
return (
<div className={cn('flex flex-col gap-y-2', className)}>
{showLabel && <Label_Shadcn_ className="text-foreground-light">Type</Label_Shadcn_>}
<Popover_Shadcn_ open={open} onOpenChange={setOpen}>
<Popover_Shadcn_ modal open={open} onOpenChange={setOpen}>
<PopoverTrigger_Shadcn_ asChild>
<Button
type={error ? 'danger' : 'default'}
Expand All @@ -186,17 +186,17 @@ const ColumnType = ({
</Button>
</PopoverTrigger_Shadcn_>
<PopoverContent_Shadcn_ className="w-[460px] p-0" side="bottom" align="center">
<ScrollArea className="h-[335px]">
<Command_Shadcn_>
<CommandInput_Shadcn_
placeholder="Search types..."
// [Joshen] Addresses style issues when this component is being used in the old Form component
// Specifically in WrapperDynamicColumns - can be cleaned up once we're no longer using that
className="!bg-transparent focus:!shadow-none focus:!ring-0"
/>
<CommandEmpty_Shadcn_>Type not found.</CommandEmpty_Shadcn_>
<Command_Shadcn_>
<CommandInput_Shadcn_
placeholder="Search types..."
// [Joshen] Addresses style issues when this component is being used in the old Form component
// Specifically in WrapperDynamicColumns - can be cleaned up once we're no longer using that
className="!bg-transparent focus:!shadow-none focus:!ring-0"
/>
<CommandEmpty_Shadcn_>Type not found.</CommandEmpty_Shadcn_>

<CommandList_Shadcn_>
<CommandList_Shadcn_>
<ScrollArea className="h-[240px]">
<CommandGroup_Shadcn_>
{POSTGRES_DATA_TYPE_OPTIONS.map((option: PostgresDataTypeOption) => (
<CommandItem_Shadcn_
Expand Down Expand Up @@ -266,9 +266,9 @@ const ColumnType = ({
</CommandGroup_Shadcn_>
</>
)}
</CommandList_Shadcn_>
</Command_Shadcn_>
</ScrollArea>
</ScrollArea>
</CommandList_Shadcn_>
</Command_Shadcn_>
</PopoverContent_Shadcn_>
</Popover_Shadcn_>

Expand Down
559 changes: 559 additions & 0 deletions apps/www/_alternatives/supabase-vs-convex.mdx

Large diffs are not rendered by default.

343 changes: 343 additions & 0 deletions apps/www/_blog/2026-01-15-read-replicas-vs-bigger-compute.mdx

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions apps/www/_events/2026-02-25-enterprise-innovation-with-bolt.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
title: 'Vibe Coding, Done Right: AI Development in Production'
meta_title: 'Vibe Coding, Done Right: AI Development in Production'
subtitle: >-
Learn how enterprise innovation teams are using AI coding tools like Bolt to build real applications on Supabase
meta_description: >-
Learn how enterprise teams use AI coding tools like Bolt to build production apps. Real customer story, governance models, and security practices.
type: webinar
onDemand: false
date: '2026-02-25T07:00:00.000-08:00'
timezone: America/Los_Angeles
duration: 45 mins
categories:
- webinar
main_cta:
{
url: 'https://attendee.gotowebinar.com/register/678318862881390429',
target: '_blank',
label: 'Register now',
}
speakers: 'chris_caruso'
---

Something strange is happening in large enterprises. Non-technical employees are building production software. CEOs are shipping features. And companies are canceling SaaS contracts worth millions.

In this webinar, you will learn how enterprise innovation teams are using AI coding tools like Bolt to build real applications on Supabase. We will show you how to rapidly prototype internal tools, how to work within the constraints of an existing design system, and how to empower non/semi-technical teams to build safely.

## Key Takeaways

- How to give non-technical teams the ability to build production software without compromising security or stability

- The governance model that makes AI-assisted development safe for enterprises

- Why prototypes built on the right foundation can go to production without being rebuilt

- How to evaluate SaaS contracts differently when building becomes cheaper than buying

- Real-world use cases for rapidly prototyping and building internal tools

- The MCP integration that connects AI coding tools directly to your database

Join us live to participate in the Q&A. Can't make it? We'll send you a link to the recording.
16 changes: 10 additions & 6 deletions apps/www/app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { getAllCMSPostSlugs, getCMSPostBySlug } from 'lib/get-cms-posts'
import { getAllPostSlugs, getPostdata, getSortedPosts } from 'lib/posts'
import type { Metadata } from 'next'
import { draftMode } from 'next/headers'
import type { Blog, BlogData, PostReturnType } from 'types/post'

import BlogPostClient from './BlogPostClient'
import { processCMSContent } from '~/lib/cms/processCMSContent'
import { CMS_SITE_ORIGIN, SITE_ORIGIN } from '~/lib/constants'
import BlogPostClient from './BlogPostClient'

import type { Metadata } from 'next'
import type { Blog, BlogData, PostReturnType } from 'types/post'

export const revalidate = 30

Expand Down Expand Up @@ -93,8 +93,12 @@ export async function generateMetadata({ params }: { params: Promise<Params> }):
const postContent = await getPostdata(slug, '_blog')
const parsedContent = matter(postContent) as unknown as MatterReturn
const blogPost = parsedContent.data
const imageField = blogPost.imgSocial ? blogPost.imgSocial : blogPost.imgThumb
const metaImageUrl = imageField ? `/images/blog/${imageField}` : undefined
const blogImage = blogPost.imgThumb || blogPost.imgSocial
const metaImageUrl = blogImage
? blogImage.startsWith('http')
? blogImage
: `${CMS_SITE_ORIGIN.replace('/api-v2', '')}${blogImage}`
: undefined

return {
title: blogPost.title,
Expand Down
22 changes: 11 additions & 11 deletions apps/www/components/Blog/BlogGridItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import dayjs from 'dayjs'
import authors from 'lib/authors.json'
import Image from 'next/image'
import Link from 'next/link'

import type Author from '~/types/author'
import type PostTypes from '~/types/post'

Expand All @@ -23,17 +24,16 @@ const BlogGridItem = ({ post }: Props) => {
}
}

const resolveImagePath = (img: string | undefined): string | null => {
if (!img) return null
return img.startsWith('/') || img.startsWith('http') ? img : `/images/blog/${img}`
}

const imageUrl = post.isCMS
? post.imgThumb
? post.imgThumb
: post.imgSocial
? post.imgSocial
: '/images/blog/blog-placeholder.png'
: post.imgThumb
? `/images/blog/${post.imgThumb}`
: post.imgSocial
? `/images/blog/${post.imgSocial}`
: '/images/blog/blog-placeholder.png'
? post.imgThumb || post.imgSocial || '/images/blog/blog-placeholder.png'
: resolveImagePath(post.imgThumb) ||
resolveImagePath(post.imgSocial) ||
'/images/blog/blog-placeholder.png'

return (
<Link
Expand All @@ -43,7 +43,7 @@ const BlogGridItem = ({ post }: Props) => {
>
<div className="flex flex-col space-y-2">
<div className="flex flex-col space-y-1">
<div className="border-default relative mb-3 w-full aspect-[2/1] lg:aspect-[5/3] overflow-hidden rounded-lg border shadow-sm">
<div className="border-default relative mb-3 w-full aspect-[1.91/1] overflow-hidden rounded-lg border shadow-sm">
<Image
fill
sizes="100%"
Expand Down
14 changes: 7 additions & 7 deletions apps/www/components/Blog/BlogPostRenderer.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
'use client'

import dayjs from 'dayjs'
import mdxComponents from 'lib/mdx/mdxComponents'
import { ChevronLeft } from 'lucide-react'
import { MDXRemote } from 'next-mdx-remote'
import type { MDXRemoteSerializeResult } from 'next-mdx-remote'
import dynamic from 'next/dynamic'
import Image from 'next/image'
import Link from 'next/link'
import { useMemo, useState } from 'react'
import { Badge } from 'ui'

import mdxComponents from 'lib/mdx/mdxComponents'

import type { MDXRemoteSerializeResult } from 'next-mdx-remote'
import type { ComponentType } from 'react'
import type { CMSAuthor, PostReturnType, ProcessedBlogData, Tag } from 'types/post'
import { Badge } from 'ui'

const ShareArticleActions = dynamic(() => import('components/Blog/ShareArticleActions'))
const CTABanner = dynamic(() => import('components/CTABanner'))
Expand Down Expand Up @@ -162,7 +160,9 @@ const BlogPostRenderer = ({
const imageUrl = isCMS
? blogMetaData.imgThumb ?? ''
: blogMetaData.imgThumb
? `/images/blog/${blogMetaData.imgThumb}`
? blogMetaData.imgThumb.startsWith('/') || blogMetaData.imgThumb.startsWith('http')
? blogMetaData.imgThumb
: `/images/blog/${blogMetaData.imgThumb}`
: ''

return (
Expand Down Expand Up @@ -264,7 +264,7 @@ const BlogPostRenderer = ({
/>
) : (
blogMetaData.imgThumb && (
<div className="hidden md:block relative mb-8 w-full aspect-video overflow-auto rounded-lg border">
<div className="hidden md:block relative mb-8 w-full aspect-[1.91/1] overflow-auto rounded-lg border">
<Image
src={imageUrl}
alt={blogMetaData.title}
Expand Down
19 changes: 9 additions & 10 deletions apps/www/components/Blog/FeaturedThumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,16 @@ function FeaturedThumb(blog: PostTypes | CMSPostTypes) {
}

function renderFeaturedThumb(blog: PostTypes, author: any[]) {
const resolveImagePath = (img: string | undefined): string | null => {
if (!img) return null
return img.startsWith('/') || img.startsWith('http') ? img : `/images/blog/${img}`
}

const imageUrl = blog.isCMS
? blog.imgThumb
? blog.imgThumb
: blog.imgSocial
? blog.imgSocial
: '/images/blog/blog-placeholder.png'
: blog.imgThumb
? `/images/blog/${blog.imgThumb}`
: blog.imgSocial
? `/images/blog/${blog.imgSocial}`
: '/images/blog/blog-placeholder.png'
? blog.imgThumb || blog.imgSocial || '/images/blog/blog-placeholder.png'
: resolveImagePath(blog.imgThumb) ||
resolveImagePath(blog.imgSocial) ||
'/images/blog/blog-placeholder.png'

return (
<div key={blog.slug} className="w-full">
Expand Down
8 changes: 7 additions & 1 deletion apps/www/components/Events/EventGridItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,13 @@ const EventGridItem = ({ event }: Props) => {
fill
sizes="100%"
quality={100}
src={event.type === 'casestudy' ? event.thumb : `/images/blog/${event.thumb}`}
src={
event.type === 'casestudy' ||
event.thumb.startsWith('/') ||
event.thumb.startsWith('http')
? event.thumb
: `/images/blog/${event.thumb}`
}
className="scale-100 object-cover overflow-hidden"
alt={`${event.title} thumbnail`}
/>
Expand Down
6 changes: 5 additions & 1 deletion apps/www/components/Solutions/PostGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ function PostGrid({ id, className, header, subheader, posts }: PostGridProps) {
{post.imgThumb && (
<div className="w-full aspect-video relative rounded-t-md dark:[mask-image:linear-gradient(to_bottom,_#000_0%,_#000_60%,_transparent_100%)]">
<Image
src={`/images/blog/${post.imgThumb}`}
src={
post.imgThumb.startsWith('/') || post.imgThumb.startsWith('http')
? post.imgThumb
: `/images/blog/${post.imgThumb}`
}
alt={post.title || ''}
className="object-cover"
fill
Expand Down
4 changes: 2 additions & 2 deletions apps/www/data/solutions/convex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ const data = {
],
ctas: [
{
label: 'View documentation',
href: 'https://supabase.com/docs',
label: 'Compare Convex and Supabase',
href: '/alternatives/supabase-vs-convex',
type: 'default' as any,
icon: <ArrowUpRight className="w-4 h-4 text-current" />,
},
Expand Down
16 changes: 9 additions & 7 deletions apps/www/layouts/comparison.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,15 @@ const LayoutComparison = ({ components, props }: Props) => {
return cat
}),
},
images: [
{
url: `https://supabase.com${basePath}/images/blog/${
props.blog.imgSocial ? props.blog.imgSocial : props.blog.imgThumb
}`,
},
],
images: (() => {
const img = props.blog.imgSocial || props.blog.imgThumb
if (!img) return []
const url =
img.startsWith('/') || img.startsWith('http')
? img
: `https://supabase.com${basePath}/images/blog/${img}`
return [{ url }]
})(),
}}
/>
<DefaultLayout>
Expand Down
7 changes: 7 additions & 0 deletions apps/www/lib/remotePatterns.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,13 @@ module.exports = [
port: '',
pathname: '**',
},
// OG Edge Function
{
protocol: 'https',
hostname: 'zhfonblqamxferhoguzj.supabase.co',
port: '',
pathname: '/functions/v1/generate-og',
},
// Dynamically generated CMS patterns based on CMS_SITE_ORIGIN
...generateCMSRemotePatterns(),
]
21 changes: 14 additions & 7 deletions apps/www/public/rss.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
<description>We are releasing Agent Skills for Postgres Best Practices to help AI coding agents write high quality, correct Postgres code.</description>
<pubDate>Wed, 21 Jan 2026 00:00:00 -0700</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/read-replicas-vs-bigger-compute</guid>
<title>When to use Read Replicas vs. bigger compute</title>
<link>https://supabase.com/blog/read-replicas-vs-bigger-compute</link>
<description>A practical guide to diagnosing database slowdowns and choosing between vertical scaling and Read Replicas based on your workload, budget, and performance bottlenecks.</description>
<pubDate>Thu, 15 Jan 2026 00:00:00 -0700</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/introducing-trae-solo-integration</guid>
<title>Introducing TRAE SOLO integration with Supabase</title>
Expand Down Expand Up @@ -2463,6 +2470,13 @@
<description>Five days of Supabase.</description>
<pubDate>Thu, 25 Mar 2021 00:00:00 -0700</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/postgresql-views</guid>
<title>Postgres Views</title>
<link>https://supabase.com/blog/postgresql-views</link>
<description>Creating and using a view in PostgreSQL.</description>
<pubDate>Wed, 18 Nov 2020 00:00:00 -0700</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/continuous-postgresql-backup-walg</guid>
<title>Continuous PostgreSQL Backups using WAL-G</title>
Expand Down Expand Up @@ -2498,13 +2512,6 @@
<description>We&apos;re releasing a new version of our Supabase client with some awesome new improvements.</description>
<pubDate>Fri, 30 Oct 2020 00:00:00 -0700</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/postgresql-views</guid>
<title>Postgres Views</title>
<link>https://supabase.com/blog/postgresql-views</link>
<description>Creating and using a view in PostgreSQL.</description>
<pubDate>Wed, 18 Nov 2020 00:00:00 -0700</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/case-study-monitoro</guid>
<title>Monitoro Built a Web Crawler Handling Millions of API Requests</title>
Expand Down
Loading