> [!IMPORTANT] > Don't merge until the OrioleDB public beta launches. Docs deploy on merge. ## What Updates the OrioleDB guide (`guides/database/orioledb`) for the public beta: - States that OrioleDB is in public beta and that OrioleDB projects have access to the same paid features as other Supabase projects. - Replaces the outdated "choose `OrioleDB Public Alpha` Postgres version" instruction and its screenshot with text steps that match the current project creation form (**Advanced Configuration** → **Postgres Type** → **Postgres with OrioleDB**). It also notes that OrioleDB can't be added to or removed from an existing project. A new screenshot will follow once the dashboard shows the beta labels. - Corrects the `orioledb.default_compress` range to `-1` to `22`. Values outside that range are rejected. - Updates the `EXPLAIN` output for the primary key lookup to match what OrioleDB returns (`Custom Scan (o_scan)`). - Replaces the benchmark chart's alt text with a description of the chart. Headings, frontmatter, and navigation are unchanged, so existing links to this page and its sections still work. ## Checked against upstream OrioleDB Checked the page's claims against the [OrioleDB docs](https://github.com/orioledb/orioledb/tree/main/doc/usage) and codebase on `main`: - The concepts section, the `orioledb.serializable` values, and the compression settings match. - The limitations link still resolves (`#current-limitations`). - Doc changes on `main` since beta17 (collations, sparse files, concurrent unique bridged indexes) don't affect claims on this page. ## Verification (`/test-the-docs`) | Snippet / step | Class | Sandbox | Result | Notes | | --- | --- | --- | --- | --- | | `create table blog_post …` | runnable-local | DinD + runner, `supabase/postgres:17.9.0.028-orioledb` | pass | Table created with the `orioledb` access method (default) | | `create index …` (2 indexes) | runnable-with-setup | same | pass | | | `insert …` + `select …` | runnable-with-setup | same | pass | Timestamp differs, as expected | | `explain` (3 statements) | runnable-with-setup | same | pass | Primary key lookup output updated in this PR to match | | `select … from pg_settings where name like 'orioledb.%'` | runnable-local | same | pass | All 10 automatically tuned settings present | | `alter database … default_compress to 1` | runnable-local | same | pass | | | Compression range `-1`–`22` | claim check | same | pass | `23` rejected: "outside the valid range (-1 .. 22)" | | User-configurable settings have `user` context | claim check | same | pass | `serializable` values match the page | | Hidden `ctid` key when no primary key is defined | claim check | same | pass | | | HNSW index via index bridging | claim check | same | fail (product bug) | Index misses rows inserted after it's created. Known upstream as orioledb/orioledb#1118, fixed after beta17. The tested image bundles an earlier OrioleDB release. Re-test on an image with beta18 before merging. | | Dashboard project creation steps | deferred | — | deferred | Needs a hosted project; labels checked against Studio source | **Tier A path:** every SQL block on the page, run in page order against the Supabase OrioleDB image. **Environment:** Docker 29.4.0 (linux/aarch64); compose sandbox from `test-the-docs`; all SQL run inside the runner container. **Build:** `pnpm build:guides-markdown` passes; the generated markdown for this page includes all changes. ## Self-review **Blockers:** none. **Before merging:** - [ ] Re-run the HNSW check on an image with OrioleDB beta18. - [ ] Re-check the page against the `beta18` tag once it's published. **Nits left for a follow-up (existing text, outside this PR's scope):** - The page spells `pg_vector`; the extension is `pgvector`. - Index support is described twice, in the top note and again under "Creating indexes". - The markdown export (`internals/markdown-schema/Admonition.ts`) drops admonition titles on every page. This PR avoids relying on a title for the beta status. Linear: DOCS-1399 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Updated the OrioleDB guide with benchmark results for an 8xlarge instance, including a 1.8x speedup and throughput data across 32–256 connections. * Clarified that OrioleDB projects have access to the same paid features as other Supabase projects, and added guidance to review its limitations. * Updated project setup instructions, noting that OrioleDB must be selected when creating a project and cannot be added later or removed. * Revised the query plan example and documented compression levels from `0` through `22`. * **Product Updates** * Updated OrioleDB’s availability stage to public beta. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Artur Zakirov <zaartur@gmail.com>
supabase.com
Overview
Refer to the Development Guide to learn how to run this site locally.
To get started copy the example env file using cp .env.local.example .env.local.
Production builds
Run pnpm build from apps/www, or pnpm build --filter=www from the repository
root. Vercel uses the app's build script by default.
prebuild refreshes remote content before Turbo hashes it. Turbo caches
build:next (Next.js, sitemaps, and the customer RSS feed), then postbuild
uploads assets even on cache hits. The outer build task stays uncached so
neither preparation nor upload can be skipped. Uploads run after caching because
the upload script removes .next/static.
Production cache reuse requires the same commit and inputs: CDN URLs include
VERCEL_GIT_COMMIT_SHA. Set FORCE_ASSET_CDN=-1 to disable local uploads.
Running build:next directly skips content preparation and uploads.
Run pnpm exec vitest run turbo-build.test.ts to check cache invalidation and
asset restoration using real pnpm, Turbo, and the upload script with fixture
generators, a stub compiler, and a fake AWS CLI.
Best practices
Images
- Resize images: All new images should be resized to only the maximum resolution needed when rendering on the frontend. Don't upload images larger than what will be displayed.
- Compress images: All new images should be compressed before committing. Use tools like Clop or ImageOptim to reduce file size without noticeable quality loss.
- Image locations: Store blog post images in
apps/www/public/images/blog/. Event images go inapps/www/public/images/events/. Customer logos go inapps/www/public/images/customers/logos/on-light/andon-dark/(see Customer Stories below).
OG image generation
Open Graph (OG) images for social sharing are handled differently across content types:
- Blog posts: Use static images via
imgSocialandimgThumbfields (see Blog posts section below) - Events: Use dynamic generation via Edge Function (with optional
og_imageoverride) - Customer stories: Use dynamic generation via Edge Function (no static option)
The og-images Edge Function (supabase/functions/og-images/) automatically generates OG images for events and customer stories. It's deployed via .github/workflows/og_images.yml when changes are made to the function code.
Development: In local development, the function runs at http://127.0.0.1:54321/functions/v1/og-images. Ensure Supabase is running locally (supabase start).
Content frontmatter image fields
Different content types use different image field conventions:
Blog posts
Blog posts support two image fields in their frontmatter:
imgSocial: Used for Open Graph and social media sharing (X, LinkedIn, etc.). These images should include text overlays since they appear standalone in social feeds without accompanying text.imgThumb: Used for internal thumbnails displayed on the blog listing pages and featured posts. These images don't need text overlays since they're always displayed alongside the post title and description.
This naming convention was introduced to replace the previously confusing thumb and og fields, which were often mixed up. The new names clearly indicate:
imgSocial: Purpose-built for social media sharing (needs text overlays)imgThumb: Optimized for site display (clean, no text overlays)
This separation allows you to optimize images for their specific use case while maintaining a clear, unambiguous naming convention.
Image path format
Always use relative paths (just the filename or subfolder/filename). The /images/blog/ prefix is added automatically by the code.
- ✅ Correct:
imgSocial: my-post/og.pngorimgSocial: og.png - ❌ Wrong:
imgSocial: /images/blog/my-post/og.png(creates double prefix)
Image fallback behavior
For site display (what visitors see):
- Priority 1:
imgThumb - Priority 2:
imgSocial(ifimgThumbis missing) - Priority 3:
/images/blog/blog-placeholder.png(if both missing)
For social sharing (Open Graph meta tags):
- Priority 1:
imgSocial - Priority 2:
imgThumb(ifimgSocialis missing) - Priority 3: No fallback (undefined)
What happens if fields are not provided?
- If only
imgThumbis provided: Site displays the image correctly, social sharing usesimgThumbas fallback - If only
imgSocialis provided: Social sharing uses it, site display uses it as fallback - If neither is provided: Site shows placeholder image, social sharing has no image
- Best practice: Provide both fields for optimal display and social sharing
Example
---
title: 'My Blog Post'
imgSocial: 2025-01-01-my-post/og.png # Relative path - with text overlay for social sharing
imgThumb: 2025-01-01-my-post/thumb.png # Relative path - without text, clean image
---
The images would be stored at:
apps/www/public/images/blog/2025-01-01-my-post/og.pngapps/www/public/images/blog/2025-01-01-my-post/thumb.png
Or if using the same image for both:
---
title: 'My Blog Post'
imgSocial: my-image.png # Stored at: apps/www/public/images/blog/my-image.png
imgThumb: my-image.png
---
Blog post dates
Use quoted YYYY-MM-DD values. date is the publication date. Set optional updated for substantive content revisions, excluding typo, link, or image fixes. It must be on or after date and supplies the sitemap and structured-data modification date. When absent, date supplies both.
Events
Events use different image fields to avoid confusion with their display patterns:
thumb: Used for event grid item thumbnails (small cards in listing)cover_url: Used for the featured event banner (large display on events page)og_image(optional): Used to override the dynamically generated OG image for social sharing
OG image generation
Events automatically generate Open Graph images using the og-images Supabase Edge Function. The function creates images dynamically based on:
- Event type (conference, hackathon, etc.)
- Title (or
meta_titleif provided) - Description (or
meta_descriptionif provided) - Date (formatted as "DD MMM YYYY" using the event's timezone)
- Duration (if provided)
If you need a custom OG image that differs from the auto-generated one, you can provide an og_image field in the frontmatter. This will override the dynamic generation.
Example:
---
title: 'Supabase Meetup'
thumb: /images/events/2025-01-meetup/thumbnail.png
cover_url: https://external-cdn.com/event-banner.jpg
og_image: /images/events/2025-01-meetup/custom-og.png # Optional override
---
Note: The og_image field is optional. If not provided, OG images are generated automatically via the Edge Function.
End-to-end checks
Content pages are loaded and scanned with axe-core by the Playwright suite in
e2e/www. Pull requests test the pages your change affects. Today the suite
enforces one accessibility rule, page-has-heading-one.
To test the pages your current branch changes:
PLAYWRIGHT_BASE_URL=https://supabase.com pnpm e2e:www
That resolves which pages to test from your branch, but reads them from
production, so it won't see your edits and will 404 on a page you just added.
Point PLAYWRIGHT_BASE_URL at your pull request's preview to test your own
content.
See e2e/www/README.md
for coverage and limits.
Go pages (/go/*)
/go/ is a system for building standalone campaign landing pages (lead generation, legal, thank-you flows). The name is intentionally generic — these pages are typically linked from ads, emails, or partner campaigns and are not part of the main site navigation.
Pages are defined as TypeScript objects (not MDX files) and validated against Zod schemas at build time.
Parts
| Location | Purpose |
|---|---|
apps/www/_go/ |
Page definitions. Each file exports a page object. index.tsx registers all pages. |
apps/www/app/go/[slug]/page.tsx |
App Router route — renders the page for a given slug, handles 404s and metadata. |
apps/www/components/Go/GoPageRenderer.tsx |
www-specific wrapper — adds the Supabase logo header and footer, registers custom section renderers. |
packages/marketing/src/go/ |
Framework-agnostic core: schemas, section components, templates, form server action. |
packages/marketing/src/crm/ |
CRM client abstraction (HubSpot + Customer.io) used by the form server action. |
Page structure
Each page specifies a template which determines its top-level layout:
lead-gen— hero + arbitrary sections (form, metrics, feature grid, tweets, social proof, etc.)thank-you— hero + sections + confetti animationlegal— hero + table-of-contents sidebar + markdown body
Pages are arrays of typed section objects. The SectionRenderer in packages/marketing dispatches each section to the right component based on its type field.
Custom renderers
The marketing package doesn't know about topTweets data or the Pages Router basePath, so the tweets section type has no default renderer. GoPageRenderer.tsx in www registers TweetsSection as a custom renderer for that type. This is the extension point for any section that requires www-specific dependencies.
Adding a new page
- Create a new file in
apps/www/_go/<category>/my-page.tsxexporting a page object. - Register it in
apps/www/_go/index.tsx. - The page will be available at
/go/<slug>automatically via static generation.
Customer Stories (Case Studies)
Customer stories are defined in MDX files (apps/www/_customers/*.mdx) and use a different approach:
- No
og_imagefield: Customer stories do NOT use static OG images - Dynamic OG generation: All customer story OG images are automatically generated using the
og-imagesSupabase Edge Function - The function creates images based on the customer
slugandtitle(ormeta_titleif provided)
Do not include an og_image field in customer story frontmatter. It will be ignored. OG images are always generated dynamically.
Logos
Customer logos are monochrome and transparent. Prefer SVG; PNG is also fine. Put each theme variant in the folder named for the background it sits on:
| Folder | Mark | Frontmatter | Shown in |
|---|---|---|---|
/images/customers/logos/on-light/ |
Dark/black | logo |
Light mode |
/images/customers/logos/on-dark/ |
Light/white | logo_inverse |
Dark mode |
Do not use coloured brand marks. Preview /customers in both themes before merging.
Icon-only assets (homepage chips, etc.) stay at /images/customers/logos/{slug}-icon.svg.
Customer story OG images are generated by the og-images Edge Function, which fetches https://supabase.com/images/customers/logos/on-dark/{slug}.png. Satori cannot rasterise SVG, so stories still need an on-dark/{slug}.png even if the site uses SVG.
Example (in apps/www/_customers/company-abc.mdx):
---
name: Company ABC
title: Company ABC built their platform with Supabase
# DO NOT include og_image - it's generated automatically
logo: /images/customers/logos/on-light/company-abc.svg
logo_inverse: /images/customers/logos/on-dark/company-abc.svg
---
Legacy Case Studies (in data/CustomerStories.ts):
imgUrl: Path to the case study image in the source data- This gets mapped to
imgThumbwhen rendered viaBlogGridItemcomponent - Case studies only need one image for site display (no separate social sharing image)
Example (in data/CustomerStories.ts):
{
type: 'Customer Story',
title: 'Company ABC built their platform with Supabase',
description: '...',
organization: 'Company ABC',
imgUrl: 'images/customers/logos/on-light/company-abc.svg', // Full path from public/
logo: '/images/customers/logos/on-light/company-abc.svg',
logo_inverse: '/images/customers/logos/on-dark/company-abc.svg',
url: '/customers/company-abc',
}