diff --git a/.github/workflows/studio-e2e-test.yml b/.github/workflows/studio-e2e-test.yml
new file mode 100644
index 0000000000000..1403a3814943e
--- /dev/null
+++ b/.github/workflows/studio-e2e-test.yml
@@ -0,0 +1,93 @@
+name: Studio E2E Tests
+on:
+ push:
+ branches: [master]
+ paths:
+ - 'packages/pg-meta/**/*'
+ - 'apps/studio/**'
+ - 'e2e/studio/**'
+ - 'pnpm-lock.yaml'
+ pull_request:
+ paths:
+ - 'packages/pg-meta/**/*'
+ - 'apps/studio/**'
+ - 'e2e/studio/**'
+ - 'pnpm-lock.yaml'
+ - '.github/workflows/studio-e2e-test.yml'
+
+# Cancel old builds on new commit for same workflow + branch/PR
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
+permissions:
+ contents: write
+
+jobs:
+ test:
+ timeout-minutes: 60
+ runs-on: ubuntu-latest
+ # Make the job non-blocking
+ continue-on-error: true
+ # Require approval only for external contributors
+ environment: ${{ github.event.pull_request.author_association != 'MEMBER' && 'Studio E2E Tests' || '' }}
+
+ env:
+ EMAIL: ${{ secrets.CI_EMAIL }}
+ PASSWORD: ${{ secrets.CI_PASSWORD }}
+ PROJECT_REF: ${{ secrets.CI_PROJECT_REF }}
+ NEXT_PUBLIC_IS_PLATFORM: true
+ NEXT_PUBLIC_API_URL: https://api.supabase.green
+ VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
+ VERCEL_PROJECT_ID: ${{ secrets.VERCEL_STUDIO_HOSTED_PROJECT_ID }}
+ NEXT_PUBLIC_HCAPTCHA_SITE_KEY: 10000000-ffff-ffff-ffff-000000000001
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4
+ name: Install pnpm
+ with:
+ run_install: false
+ - name: Use Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: '.nvmrc'
+ cache: 'pnpm'
+
+ - name: Install dependencies
+ run: pnpm i
+
+ - name: Install Vercel CLI
+ run: pnpm add --global vercel@latest
+
+ - name: Pull Vercel Environment Information (Preview)
+ run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
+
+ - name: Build Project Artifacts for Vercel
+ run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
+
+ - name: Deploy Project to Vercel and Get URL
+ id: deploy_vercel
+ run: |
+ DEPLOY_URL=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})
+ echo "Vercel Preview URL: $DEPLOY_URL"
+ echo "DEPLOY_URL=$DEPLOY_URL" >> $GITHUB_OUTPUT
+
+ - name: Install Playwright Browsers
+ run: pnpm -C e2e/studio exec playwright install --with-deps
+
+ - name: Run Playwright tests
+ id: playwright
+ env:
+ AUTHENTICATION: true
+ STUDIO_URL: ${{ steps.deploy_vercel.outputs.DEPLOY_URL }}/dashboard
+ run: pnpm e2e
+
+ - uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: playwright-artifacts
+ path: |
+ e2e/studio/playwright-report/
+ e2e/studio/test-results/
+ retention-days: 7
diff --git a/apps/docs/content/guides/auth/quickstarts/react.mdx b/apps/docs/content/guides/auth/quickstarts/react.mdx
index bc06bf2e736dc..d60a17e4e5145 100644
--- a/apps/docs/content/guides/auth/quickstarts/react.mdx
+++ b/apps/docs/content/guides/auth/quickstarts/react.mdx
@@ -27,22 +27,21 @@ hideToc: true
+
-
+ Create a React app using [Vite](https://vitejs.dev/).
- Create a React app using the `create-react-app` command.
+
-
+
-
+ ```bash name=Terminal
+ npm create vite@latest my-app -- --template react
- ```bash name=Terminal
- npx create-react-app my-app
- ```
+ ```
-
-
-
+
+
diff --git a/apps/docs/content/guides/realtime/postgres-changes.mdx b/apps/docs/content/guides/realtime/postgres-changes.mdx
index a75c940404d79..395deda2828cd 100644
--- a/apps/docs/content/guides/realtime/postgres-changes.mdx
+++ b/apps/docs/content/guides/realtime/postgres-changes.mdx
@@ -1570,7 +1570,7 @@ supabase
schema: 'public',
table: 'colors',
filter: PostgresChangeFilter(
- type: PostgresChangeFilterType.lte,
+ type: PostgresChangeFilterType.inFilter,
column: 'name',
value: ['red', 'blue', 'yellow'],
),
diff --git a/apps/docs/public/humans.txt b/apps/docs/public/humans.txt
index 604be8a1f41af..fdd236e51a019 100644
--- a/apps/docs/public/humans.txt
+++ b/apps/docs/public/humans.txt
@@ -64,6 +64,7 @@ Kamil Ogórek
Kang Ming Tay
Karan S
Karlo Ison
+Katerina Skroumpelou
Kevin Brolly
Kevin Grüneberg
Lakshan Perera
diff --git a/apps/www/_blog/2025-07-18-persistent-storage-for-faster-edge-functions.mdx b/apps/www/_blog/2025-07-18-persistent-storage-for-faster-edge-functions.mdx
new file mode 100644
index 0000000000000..ad80a67b047fc
--- /dev/null
+++ b/apps/www/_blog/2025-07-18-persistent-storage-for-faster-edge-functions.mdx
@@ -0,0 +1,153 @@
+---
+title: 'Persistent Storage and 97% Faster Cold Starts for Edge Functions'
+description: 'Mount S3-compatible buckets as persistent file storage in Edge Functions with up to 97% faster cold start times.'
+categories:
+ - product
+ - launch-week
+ - edge-functions
+tags:
+ - launch-week
+ - edge-functions
+ - storage
+date: '2025-07-18:00:00'
+toc_depth: 3
+author: laktek,nyannyacha
+image: launch-week-15/day-5-persistent-storage-for-functions/og.jpg
+thumb: launch-week-15/day-5-persistent-storage-for-functions/thumb.png
+launchweek: '15'
+---
+
+Today, we are introducing Persistent Storage and up to 97% faster cold start times for Edge Functions. Previously, Edge Functions only supported ephemeral file storage by writing to `/tmp` directory. Many common libraries for performing tasks, such as zipping/unzipping files and image transformations, are built to work with persistent file storage, so making them work with Edge Functions required extra steps.
+
+The persistent storage option is built on top of the S3 protocol. It allows you to mount any [S3-compatible bucket](https://supabase.com/docs/guides/storage/s3/compatibility), including [Supabase Storage Buckets](https://supabase.com/docs/guides/storage), as a directory for your Edge Functions. You can perform operations such as reading and writing files to the mounted buckets as you would in a POSIX file system.
+
+```tsx
+// read from S3 bucket
+const data = await Deno.readFile('/s3/my-bucket/results.csv')
+
+// make a directory
+await Deno.mkdir('/s3/my-bucket/sub-dir')
+
+// write to S3 bucket
+await Deno.writeTextFile('/s3/my-bucket/demo.txt', 'hello world')
+```
+
+
+
+
+
+## How to configure
+
+To access an S3 bucket from Edge Functions, you must set the following as environment variables in Edge Function Secrets.
+
+- `S3FS_ENDPOINT_URL`
+- `S3FS_REGION`
+- `S3FS_ACCESS_KEY_ID`
+- `S3FS_SECRET_ACCESS_KEY`
+
+If you are using Supabase Storage, [follow this guide](https://supabase.com/docs/guides/storage/s3/authentication) to enable and create an access key and id.
+
+## Use Case: SQLite in Edge Functions
+
+The S3 File System simplifies workflows that involve reading and transforming data stored in an S3 bucket.
+
+For example, imagine you are building an IoT app where a device backs up its SQLite database to S3. You can set up a scheduled Edge Function to read this data and then push the data to your primary Postgres database for aggregates and reporting.
+
+```tsx
+// Following example is simplified for readability
+
+import { DB } from "https://deno.land/x/sqlite@v3.9.1/mod.ts";
+import { supabase } from '../shared/client.ts'
+
+const today = new Date().toISOString().split('T')[0]
+const backupDBPath = `backups/backup-${today}.db`
+
+// Use S3 FS to read the Sqlite DB
+const data = Deno.readFileSync(`/s3/${backupDBPath}`);
+
+// Create an in-memory SQLite from the data downloaded from S3
+// This is faster than directly reading from S3
+const db = new DB();
+db.deserialize(data);
+
+function calculateStats(rows: IoTData[], date: string): StatsSummary {
+ // ....
+}
+
+Deno.serve(async (req)=>{
+ // Assuming IoT data is stored in a table called 'sensor_data'
+ const rows = db.queryEntries(`
+ SELECT * FROM sensor_data
+ WHERE date(timestamp) = date('now', 'localtime')
+ `)
+
+ // Calculate statistics
+ const stats = calculateStats(rows, today)
+
+ // Insert stats into Supabase
+ const { data, error } = await supabase
+ .from('iot_daily_stats')
+ .insert([stats])
+
+ return new Response("OK);
+});
+
+```
+
+## 97% Faster Function Boot Times, Even Under Load
+
+Previously, Edge Functions with large dependencies or doing preparation work at the start (e.g., parsing/loading configs, initializing AI models) would incur a noticeable boot delay. Sometimes, these slow neighbors can impact other functions running on the same machine. All JavaScript _workers_ in the Supabase Edge Functions Runtime were cooperatively scheduled on the same [**Tokio thread pool**](https://github.com/tokio-rs/tokio). If one worker had heavy startup logic, such as parsing JavaScript modules or running synchronous operations, it could delay every worker scheduled after. This led to occasional long‑tail latency spikes in high-traffic projects.
+
+To address this issue, we moved workers which are still performing initial script evaluation onto a dedicated blocking pool. This approach prevents heavy initialization tasks from blocking the Tokio thread, significantly reducing boot time spikes for other functions.
+
+### The result
+
+Boot times are now more predictable and wait times for cold starts are now much faster. Here’s a result of a [benchmark](https://github.com/supabase/edge-runtime/blob/develop/k6/specs/mixed.ts) we did to compare boot times before and after these changes.
+
+| Metric | Before | After | (Delta) |
+| ---------------- | ---------- | --------- | --------- |
+| **Avg** | **870 ms** | **42 ms** | **95 %** |
+| **P95** | 8,502 ms | 86 ms | **99 %** |
+| **P99** | 15,069 ms | 460 ms | **97 %** |
+| **Worst** | 24,300 ms | 1 630 ms | **93 %** |
+| **Spikes > 1 s** | 47 % | 4 % | **43 pp** |
+
+## Support for Synchronous APIs
+
+By offloading expensive compute at function boot time onto a separate pool, we were able to enable the use of synchronous File APIs during function boot time. Some libraries only support synchronous File APIs (eg, SQLite), and this would allow you to set them up on Edge Functions before it starts processing requests.
+
+You can now safely use the following synchronous Deno APIs (and their Node counterparts) _during_ initial script evaluation:
+
+- Deno.statSync
+- Deno.removeSync
+- Deno.writeFileSync
+- Deno.writeTextFileSync
+- Deno.readFileSync
+- Deno.readTextFileSync
+- Deno.mkdirSync
+- Deno.makeTempDirSync
+- Deno.readDirSync
+
+**Keep in mind** that the sync APIs are available only during initial script evaluation and aren’t supported in callbacks like HTTP handlers or setTimeout.
+
+```tsx
+Deno.statSync('...') // ✅
+
+setTimeout(() => {
+ Deno.statSync('...') // 💣 ERROR! Deno.statSync is blocklisted on the current context
+})
+
+Deno.serve(() => {
+ Deno.statSync('...') // 💣 ERROR! Deno.statSync is blocklisted on the current context
+})
+```
+
+## Try it on Preview Today
+
+These changes will be rolled out along with the Deno 2 upgrade to all clusters within the next 2 weeks. Meanwhile, you can use the Preview cluster if you'd like to try them out today. Please see [this guide](https://github.com/orgs/supabase/discussions/36814) on how to test your functions in Preview cluster.
diff --git a/apps/www/components/Hero/Hero.tsx b/apps/www/components/Hero/Hero.tsx
index 547659d59bc47..470e4e20f2d04 100644
--- a/apps/www/components/Hero/Hero.tsx
+++ b/apps/www/components/Hero/Hero.tsx
@@ -19,7 +19,12 @@ const Hero = () => {
+ Day 5:
+ {announcement.launch}
+ >
+ }
className="lg:-mt-8 mb-4 lg:mb-0"
hasArrow
/>
diff --git a/apps/www/components/LaunchWeek/15/LW15MainStage.tsx b/apps/www/components/LaunchWeek/15/LW15MainStage.tsx
index be52863956342..c366ef1eb82e3 100644
--- a/apps/www/components/LaunchWeek/15/LW15MainStage.tsx
+++ b/apps/www/components/LaunchWeek/15/LW15MainStage.tsx
@@ -198,7 +198,7 @@ const CardsSlider: React.FC = ({
ref={swiperRef}
onSwiper={setControlledSwiper}
modules={[Controller, Navigation, A11y]}
- initialSlide={3}
+ initialSlide={4}
spaceBetween={8}
slidesPerView={1.5}
breakpoints={{
diff --git a/apps/www/components/LaunchWeek/15/data/lw15_data.tsx b/apps/www/components/LaunchWeek/15/data/lw15_data.tsx
index f1f32dc2a2ea0..977ae334fafdd 100644
--- a/apps/www/components/LaunchWeek/15/data/lw15_data.tsx
+++ b/apps/www/components/LaunchWeek/15/data/lw15_data.tsx
@@ -54,7 +54,7 @@ export interface WeekDayProps {
steps: StepProps[] | []
}
-export const endOfLW13Hackathon = '2025-04-04T23:59:59.999-08:00'
+export const endOfLW13Hackathon = '2025-07-04T23:59:59.999-08:00'
const days: (isDark?: boolean) => WeekDayProps[] = (isDark = true) => [
{
@@ -66,7 +66,7 @@ const days: (isDark?: boolean) => WeekDayProps[] = (isDark = true) => [
hasCountdown: false,
blog: '/blog/jwt-signing-keys',
date: 'Monday',
- published_at: '2025-03-31T07:00:00.000-07:00',
+ published_at: '2025-07-14T07:00:00.000-07:00',
title: 'Introducing JWT Signing Keys',
description: '',
links: [
@@ -97,7 +97,7 @@ const days: (isDark?: boolean) => WeekDayProps[] = (isDark = true) => [
hasCountdown: false,
blog: '/blog/analytics-buckets',
date: 'Tuesday',
- published_at: '2025-04-01T07:00:00.000-07:00',
+ published_at: '2025-07-15T07:00:00.000-07:00',
title: 'Introducing Supabase Analytics Buckets with Iceberg Support',
description: '',
links: [
@@ -128,7 +128,7 @@ const days: (isDark?: boolean) => WeekDayProps[] = (isDark = true) => [
hasCountdown: false,
blog: '/blog/branching-2-0',
date: 'Wednesday',
- published_at: '2025-04-02T07:00:00.000-07:00',
+ published_at: '2025-07-16T07:00:00.000-07:00',
title: 'Introducing Branching 2.0',
description: '',
links: [
@@ -155,11 +155,11 @@ const days: (isDark?: boolean) => WeekDayProps[] = (isDark = true) => [
d: 4,
dd: 'Thu',
shipped: true,
- isToday: true,
+ isToday: false,
hasCountdown: false,
blog: '/blog/new-observability-features-in-supabase',
date: 'Thursday',
- published_at: '2025-04-03T07:00:00.000-07:00',
+ published_at: '2025-07-17T07:00:00.000-07:00',
title: 'Introducing New Observability Features in Supabase',
description: '',
links: [
@@ -185,23 +185,23 @@ const days: (isDark?: boolean) => WeekDayProps[] = (isDark = true) => [
id: 'day-5',
d: 5,
dd: 'Fri',
- shipped: false,
- isToday: false,
+ shipped: true,
+ isToday: true,
hasCountdown: false,
- blog: '/blog/',
+ blog: '/blog/persistent-storage-for-faster-edge-functions',
date: 'Friday',
- published_at: '2025-04-04T07:00:00.000-07:00',
- title: '',
+ published_at: '2025-07-18T07:00:00.000-07:00',
+ title: 'Introducing Persistent Storage for Edge Functions',
description: '',
links: [
{
type: 'video',
- href: '',
+ href: 'h3mQrDC4g14',
+ },
+ {
+ type: 'xSpace',
+ href: 'https://x.com/i/spaces/1jMJgkeNXAbJL',
},
- // {
- // type: 'xSpace',
- // href: 'https://twitter.com/i/spaces/',
- // },
],
steps: [
{
diff --git a/apps/www/lib/redirects.js b/apps/www/lib/redirects.js
index 701b936a4e1dd..5955e6143068e 100644
--- a/apps/www/lib/redirects.js
+++ b/apps/www/lib/redirects.js
@@ -1540,6 +1540,11 @@ module.exports = [
source: '/docs/guides/functions/best-practices',
destination: '/docs/guides/functions/quickstart',
},
+ {
+ permanent: true,
+ source: '/docs/guides/functions/local-quickstart',
+ destination: '/docs/guides/functions/quickstart',
+ },
{
permanent: true,
source: '/projects',
diff --git a/apps/www/public/images/blog/launch-week-15/day-5-persistent-storage-for-functions/og.png b/apps/www/public/images/blog/launch-week-15/day-5-persistent-storage-for-functions/og.png
new file mode 100644
index 0000000000000..acd167aacfb4a
Binary files /dev/null and b/apps/www/public/images/blog/launch-week-15/day-5-persistent-storage-for-functions/og.png differ
diff --git a/apps/www/public/images/blog/launch-week-15/day-5-persistent-storage-for-functions/thumb.png b/apps/www/public/images/blog/launch-week-15/day-5-persistent-storage-for-functions/thumb.png
new file mode 100644
index 0000000000000..c83534509dacf
Binary files /dev/null and b/apps/www/public/images/blog/launch-week-15/day-5-persistent-storage-for-functions/thumb.png differ
diff --git a/apps/www/public/rss.xml b/apps/www/public/rss.xml
index aee1d2e203207..bfd1b14f68c5c 100644
--- a/apps/www/public/rss.xml
+++ b/apps/www/public/rss.xml
@@ -5,9 +5,16 @@
https://supabase.com
Latest news from Supabaseen
- Thu, 17 Jul 2025 00:00:00 -0700
+ Fri, 18 Jul 2025 00:00:00 -0700
+ https://supabase.com/blog/persistent-storage-for-faster-edge-functions
+ Persistent Storage and 97% Faster Cold Starts for Edge Functions
+ https://supabase.com/blog/persistent-storage-for-faster-edge-functions
+ Mount S3-compatible buckets as persistent file storage in Edge Functions with up to 97% faster cold start times.
+ Fri, 18 Jul 2025 00:00:00 -0700
+
+https://supabase.com/blog/algolia-connector-for-supabaseAlgolia Connector for Supabase
https://supabase.com/blog/algolia-connector-for-supabase
@@ -252,20 +259,6 @@
Technical deep dive into the new DBOS integration for SupabaseTue, 10 Dec 2024 00:00:00 -0700
-
- https://supabase.com/blog/database-build-v2
- database.build v2: Bring-your-own-LLM
- https://supabase.com/blog/database-build-v2
- Use any OpenAI API compatible LLMs in database.build
- Fri, 06 Dec 2024 00:00:00 -0700
-
-
- https://supabase.com/blog/restore-to-a-new-project
- Restore to a New Project
- https://supabase.com/blog/restore-to-a-new-project
- Effortlessly Clone Data into a New Supabase Project
- Fri, 06 Dec 2024 00:00:00 -0700
-https://supabase.com/blog/hack-the-baseHack the Base! with Supabase
@@ -280,6 +273,20 @@
Highlights from Launch Week 13Fri, 06 Dec 2024 00:00:00 -0700
+
+ https://supabase.com/blog/database-build-v2
+ database.build v2: Bring-your-own-LLM
+ https://supabase.com/blog/database-build-v2
+ Use any OpenAI API compatible LLMs in database.build
+ Fri, 06 Dec 2024 00:00:00 -0700
+
+
+ https://supabase.com/blog/restore-to-a-new-project
+ Restore to a New Project
+ https://supabase.com/blog/restore-to-a-new-project
+ Effortlessly Clone Data into a New Supabase Project
+ Fri, 06 Dec 2024 00:00:00 -0700
+https://supabase.com/blog/supabase-queuesSupabase Queues
diff --git a/packages/ui-patterns/src/Banners/data.json b/packages/ui-patterns/src/Banners/data.json
index f426df2e8d5da..ab01eb3abafe6 100644
--- a/packages/ui-patterns/src/Banners/data.json
+++ b/packages/ui-patterns/src/Banners/data.json
@@ -1,6 +1,6 @@
{
- "text": "LW15: Day 4",
- "launch": "New Observability Features",
+ "text": "LW15: Day 5",
+ "launch": "Persistent Storage for Edge Functions",
"launchDate": "2025-07-17T08:00:00.000-07:00",
"link": "/launch-week#main-stage",
"cta": "Learn more"