apps/www/README.md
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.
apps/www/public/images/blog/. Event images go in apps/www/public/images/events/.Open Graph (OG) images for social sharing are handled differently across content types:
imgSocial and imgThumb fields (see Blog posts section below)og_image override)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).
Different content types use different image field conventions:
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.
imgSocial: my-post/og.png or imgSocial: og.pngimgSocial: /images/blog/my-post/og.png (creates double prefix)Image fallback behavior
For site display (what visitors see):
imgThumbimgSocial (if imgThumb is missing)/images/blog/blog-placeholder.png (if both missing)For social sharing (Open Graph meta tags):
imgSocialimgThumb (if imgSocial is missing)What happens if fields are not provided?
imgThumb is provided: Site displays the image correctly, social sharing uses imgThumb as fallbackimgSocial is provided: Social sharing uses it, site display uses it as fallbackExample
---
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.pngOr 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
---
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 sharingOG image generation
Events automatically generate Open Graph images using the og-images Supabase Edge Function. The function creates images dynamically based on:
meta_title if provided)meta_description 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.
/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.
| 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. |
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 bodyPages are arrays of typed section objects. The SectionRenderer in packages/marketing dispatches each section to the right component based on its type field.
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.
apps/www/_go/<category>/my-page.tsx exporting a page object.apps/www/_go/index.tsx./go/<slug> automatically via static generation.Customer stories are defined in MDX files (apps/www/_customers/*.mdx) and use a different approach:
og_image field: Customer stories do NOT use static OG imagesog-images Supabase Edge Functionslug and title (or meta_title if provided)Do not include an og_image field in customer story frontmatter. It will be ignored. OG images are always generated dynamically.
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/company-abc.png
---
Legacy Case Studies (in data/CustomerStories.ts):
imgUrl: Path to the case study image in the source dataimgThumb when rendered via BlogGridItem componentExample (in data/CustomerStories.ts):
{
type: 'Customer Story',
title: 'Company ABC built their platform with Supabase',
description: '...',
organization: 'Company ABC',
imgUrl: 'images/customers/logos/company-abc.png', // Full path from public/
logo: '/images/customers/logos/company-abc.png',
url: '/customers/company-abc',
}