diff --git a/apps/design-system/README.md b/apps/design-system/README.md
index 0dd571441fe..96a8eaf8fef 100644
--- a/apps/design-system/README.md
+++ b/apps/design-system/README.md
@@ -2,7 +2,7 @@
Design resources for building consistent user experiences at Supabase.
-## Getting Started
+## Getting started
First, make a copy of _.env.local.example_ and name it _env.local_. Then install any required packages and start the development server:
diff --git a/apps/design-system/content/docs/icons.mdx b/apps/design-system/content/docs/icons.mdx
index f9df03365a4..5e020a680d4 100644
--- a/apps/design-system/content/docs/icons.mdx
+++ b/apps/design-system/content/docs/icons.mdx
@@ -11,14 +11,108 @@ description: Icons make actions and navigation across Supabase easier.
## Tints
-Destructive actions, such as deleting an API key, don’t need to be [tinted](color-usage#text) with `text-destructive` because there should be a confirmation dialog as a failsafe right after.
+Use classes just like you would for [text](color-usage#text) to tint icons. For example:
-## UI Icons
+```jsx
+
+```
-We rely on Lucide icons for most of our UI icons.
+Just like text, don’t tint icons with `text-destructive` for destructive actions. There should be a confirmation dialog right after which can handle the destructive styling.
-## Custom Icons
+## UI icons
-Tap on an icon below to copy the JSX, SVG, or import path.
+We rely on [Lucide](https://lucide.dev/icons/) for any standard UI icon needs.
+
+## Custom icons
+
+Create and use custom icons when Lucide doesn’t have the icon you need. Tap on an icon below to copy the JSX, SVG, or import path.
+
+### Usage
+
+```jsx
+import { ReplaceCode, InsertCode, BucketAdd } from 'icons'
+
+function app() {
+ return (
+ <>
+
+
+
+ >
+ )
+}
+```
+
+**Default props**: All icons have `strokeWidth={2}` and `size={24}` by default. Override these props as needed for your use case.
+
+### Adding new custom icons
+
+To add a new custom icon to the Supabase icon library:
+
+1. **Create SVG file**: Add your SVG file to `packages/icons/src/raw-icons/` with a kebab-case name (e.g., `my-new-icon.svg`). Make sure it has follows these exact requirements:
+
+ - Exported at 24x24px with `viewBox="0 0 24 24"`
+ - Uses `stroke="currentColor"` for strokes (no hardcoded colors)
+ - Uses `fill="none"` for fills (no hardcoded colors)
+ - Icon content is optically centered and around 18x18px within the 24x24 frame
+ - Any unnecessary elements like ``, ``, and `` wrappers have been removed
+ - SVG structure is as simple as possible with just `` elements
+
+Just leave attributes like `stroke-width` as they are. The conversion to camel-case (for React compatibility) is handled by the below build process.
+
+2. **Build the component**: Run `npm run build:icons` from inside the `packages/icons` directory
+
+3. **Use the icon**: Import and use like any other icon:
+
+ ```jsx
+ import { MyNewIcon } from 'icons'
+ ;
+ ```
+
+### SVG design guidelines
+
+Icons should:
+
+- Always be exported 24x24px
+- Have an icon inside that frame that’s around 18x18px(ish)
+- Use clean, simple paths without unnecessary wrapper elements
+
+#### Bad example ❌
+
+Notice the hardcoded colors, unnecessary backgrounds, and complex structure:
+
+```svg
+
+```
+
+#### Good example ✅
+
+Clean structure with `currentColor` and proper attributes:
+
+```svg
+
+```
+
+{/* This is still wrong: */}
+
+```svg
+
+```
+
+### Troubleshooting
+
+If your SVG specifies `stroke-width` attributes, they will override the component's `strokeWidth` prop. Remove stroke attributes from individual paths to let the component control them.
diff --git a/apps/design-system/styles/mdx.css b/apps/design-system/styles/mdx.css
index afac3b50ede..84391167b6f 100644
--- a/apps/design-system/styles/mdx.css
+++ b/apps/design-system/styles/mdx.css
@@ -15,7 +15,7 @@
}
[data-rehype-pretty-code-fragment] {
- @apply relative text-white;
+ @apply relative;
}
[data-rehype-pretty-code-fragment] code {
diff --git a/apps/studio/components/interfaces/Home/ProjectUsage.tsx b/apps/studio/components/interfaces/Home/ProjectUsage.tsx
index 1ee9a4ddd10..346332575d8 100644
--- a/apps/studio/components/interfaces/Home/ProjectUsage.tsx
+++ b/apps/studio/components/interfaces/Home/ProjectUsage.tsx
@@ -1,6 +1,7 @@
import dayjs from 'dayjs'
import sumBy from 'lodash/sumBy'
-import { Archive, ChevronDown, Database, Key, Zap } from 'lucide-react'
+import { ChevronDown } from 'lucide-react'
+import { Auth, Database, Realtime, Storage } from 'icons'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useState } from 'react'
@@ -200,7 +201,7 @@ const ProjectUsage = () => {
-
+
}
title="Database"
@@ -226,7 +227,7 @@ const ProjectUsage = () => {
-
+
}
title="Auth"
@@ -252,7 +253,7 @@ const ProjectUsage = () => {
-
+
}
title="Storage"
@@ -278,7 +279,7 @@ const ProjectUsage = () => {
-
+
}
title="Realtime"
diff --git a/apps/studio/components/interfaces/HomeNew/ProjectUsageSection.tsx b/apps/studio/components/interfaces/HomeNew/ProjectUsageSection.tsx
index 67f46bdbb20..b29c45a6761 100644
--- a/apps/studio/components/interfaces/HomeNew/ProjectUsageSection.tsx
+++ b/apps/studio/components/interfaces/HomeNew/ProjectUsageSection.tsx
@@ -1,5 +1,5 @@
import dayjs from 'dayjs'
-import { Archive, ChevronDown, Code, Database, Key, Zap } from 'lucide-react'
+import { ChevronDown } from 'lucide-react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useMemo, useState } from 'react'
@@ -77,7 +77,6 @@ type ServiceKey = 'db' | 'functions' | 'auth' | 'storage' | 'realtime'
type ServiceEntry = {
key: ServiceKey
title: string
- icon: React.ReactNode
href?: string
route: string
enabled: boolean
@@ -159,7 +158,7 @@ export const ProjectUsageSection = () => {
{
key: 'db',
title: 'Database requests',
- icon: ,
+
href: `/project/${projectRef}/editor`,
route: '/logs/postgres-logs',
enabled: true,
@@ -167,14 +166,12 @@ export const ProjectUsageSection = () => {
{
key: 'functions',
title: 'Functions requests',
- icon: ,
route: '/logs/edge-functions-logs',
enabled: true,
},
{
key: 'auth',
title: 'Auth requests',
- icon: ,
href: `/project/${projectRef}/auth/users`,
route: '/logs/auth-logs',
enabled: authEnabled,
@@ -182,7 +179,6 @@ export const ProjectUsageSection = () => {
{
key: 'storage',
title: 'Storage requests',
- icon: ,
href: `/project/${projectRef}/storage/buckets`,
route: '/logs/storage-logs',
enabled: storageEnabled,
@@ -190,7 +186,6 @@ export const ProjectUsageSection = () => {
{
key: 'realtime',
title: 'Realtime requests',
- icon: ,
route: '/logs/realtime-logs',
enabled: true,
},
diff --git a/apps/studio/components/interfaces/Storage/EmptyBucketState.tsx b/apps/studio/components/interfaces/Storage/EmptyBucketState.tsx
index 3b4e1a61a65..32a1b30ff01 100644
--- a/apps/studio/components/interfaces/Storage/EmptyBucketState.tsx
+++ b/apps/studio/components/interfaces/Storage/EmptyBucketState.tsx
@@ -1,3 +1,4 @@
+import { BucketAdd } from 'icons'
import { CreateBucketModal } from './CreateBucketModal'
import { BUCKET_TYPES } from './Storage.constants'
@@ -9,10 +10,13 @@ export const EmptyBucketState = ({ bucketType }: EmptyBucketStateProps) => {
const config = BUCKET_TYPES[bucketType]
return (
-