Repository: supabase/cli
Pull request #2134 (2024-04-09 02:09:50)

Prod deploy
- **fix: bump gotrue version 2.145.0**
- **chore(deps): bump google.golang.org/grpc from 1.62.1 to 1.63.0 (#2117)**
- **chore: handle expo env vars in bootstrap.**
- **Apply suggestions from code review**
- **chore(deps): bump golang.org/x/mod from 0.16.0 to 0.17.0 (#2123)**
- **chore(deps): bump golang.org/x/term from 0.18.0 to 0.19.0 (#2124)**
- **chore(deps): bump golang.org/x/oauth2 from 0.18.0 to 0.19.0 (#2125)**
- **feat: add anonymous sign-ins config (#2126)**
- **fix(functions): use supabase temp folder to avoid permission error**
- **fix(functions): unbundle to slug directory by default**
- **fix(studio): bump studio version (#2133)**



Patch:
diff --git a/api/beta.yaml b/api/beta.yaml
index f6a44541..521b8f68 100644
--- a/api/beta.yaml
+++ b/api/beta.yaml
@@ -2322,6 +2322,11 @@ components:
         kps_enabled:
           type: boolean
           deprecated: true
+        template_url:
+          template_url:
+          type: string
+          description: Template URL used to create the project from the CLI.
+          example: https://github.com/supabase/supabase/tree/master/examples/slack-clone/nextjs-slack-clone
       required:
         - db_pass
         - name
diff --git a/cmd/bootstrap.go b/cmd/bootstrap.go
index 8fdfac61..003713af 100644
--- a/cmd/bootstrap.go
+++ b/cmd/bootstrap.go
@@ -7,6 +7,7 @@ import (
 	"os/signal"
 	"strings"
 
+	"github.com/go-errors/errors"
 	"github.com/spf13/afero"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
@@ -15,7 +16,11 @@ import (
 )
 
 var (
-	templateUrl string
+	starter = bootstrap.StarterTemplate{
+		Name:        "scratch",
+		Description: "An empty project from scratch.",
+		Start:       "supabase start",
+	}
 
 	bootstrapCmd = &cobra.Command{
 		GroupID: groupQuickStart,
@@ -41,16 +46,19 @@ var (
 				name := strings.ToLower(args[0])
 				for _, t := range templates {
 					if t.Name == name {
-						templateUrl = t.Url
+						starter = t
+						break
 					}
 				}
-			}
-			if len(templateUrl) == 0 {
+				if name != starter.Name {
+					return errors.New("Invalid template: " + args[0])
+				}
+			} else {
 				if err := promptStarterTemplate(ctx, templates); err != nil {
 					return err
 				}
 			}
-			return bootstrap.Run(ctx, templateUrl, afero.NewOsFs())
+			return bootstrap.Run(ctx, starter, afero.NewOsFs())
 		},
 	}
 )
@@ -73,8 +81,8 @@ func promptStarterTemplate(ctx context.Context, templates []bootstrap.StarterTem
 	}
 	items = append(items, utils.PromptItem{
 		Index:   len(items),
-		Summary: "scratch",
-		Details: "An empty project from scratch.",
+		Summary: starter.Name,
+		Details: starter.Description,
 	})
 	title := "Which starter template do you want to use?"
 	choice, err := utils.PromptChoice(ctx, title, items)
@@ -82,7 +90,7 @@ func promptStarterTemplate(ctx context.Context, templates []bootstrap.StarterTem
 		return err
 	}
 	if choice.Index < len(templates) {
-		templateUrl = templates[choice.Index].Url
+		starter = templates[choice.Index]
 	}
 	return nil
 }
diff --git a/docs/supabase/migration/repair.md b/docs/supabase/migration/repair.md
index f6e7dd3b..981bb9cb 100644
--- a/docs/supabase/migration/repair.md
+++ b/docs/supabase/migration/repair.md
@@ -6,19 +6,21 @@ Requires your local project to be linked to a remote database by running `supaba
 
 If your local and remote migration history goes out of sync, you can repair the remote history by marking specific migrations as `--status applied` or `--status reverted`. Marking as `reverted` will delete an existing record from the migration history table while marking as `applied` will insert a new record.
 
-For example, your migration history table may look like this after running `db pull` for the first time.
+For example, your migration history may look like the table below, with missing entries in either local or remote.
 
 ```bash
 $ supabase migration list
         LOCAL      │     REMOTE     │     TIME (UTC)
   ─────────────────┼────────────────┼──────────────────────
-    20230103054303 │ 20230103054303 │ 2023-01-03 05:43:03
+                   │ 20230103054303 │ 2023-01-03 05:43:03
+   20230103054315  │                │ 2023-01-03 05:43:15
 ```
 
 To reset your migration history to a clean state, first delete your local migration file.
 
 ```bash
-$ rm supabase/migrations/20230103054303_remote_commit.sql
+$ rm supabase/migrations/20230103054315_remote_commit.sql
+
 $ supabase migration list
         LOCAL      │     REMOTE     │     TIME (UTC)
   ─────────────────┼────────────────┼──────────────────────
@@ -29,10 +31,27 @@ Then mark the remote migration `20230103054303` as reverted.
 
 ```bash
 $ supabase migration repair 20230103054303 --status reverted
-Repaired migration history: 20230103054303 => reverted
+Connecting to remote database...
+Repaired migration history: [20220810154537] => reverted
+Finished supabase migration repair.
+
 $ supabase migration list
         LOCAL      │     REMOTE     │     TIME (UTC)
   ─────────────────┼────────────────┼──────────────────────
 ```
 
 Now you can run `db pull` again to dump the remote schema as a local migration file.
+
+```bash
+$ supabase db pull
+Connecting to remote database...
+Schema written to supabase/migrations/20240414044403_remote_schema.sql
+Update remote migration history table? [Y/n]
+Repaired migration history: [20240414044403] => applied
+Finished supabase db pull.
+
+$ supabase migration list
+        LOCAL      │     REMOTE     │     TIME (UTC)
+  ─────────────────┼────────────────┼──────────────────────
+    20240414044403 │ 20240414044403 │ 2024-04-14 04:44:03
+```
diff --git a/docs/templates/examples.yaml b/docs/templates/examples.yaml
index 25425f7b..d0588b6f 100644
--- a/docs/templates/examples.yaml
+++ b/docs/templates/examples.yaml
@@ -222,6 +222,39 @@ supabase-db-lint:
           ]
         }
       ]
+supabase-db-pull:
+  - id: basic-usage
+    name: Basic usage
+    code: supabase db pull
+    response: |
+      Connecting to remote database...
+      Schema written to supabase/migrations/20240414044403_remote_schema.sql
+      Update remote migration history table? [Y/n]
+      Repaired migration history: [20240414044403] => applied
+      Finished supabase db pull.
+      The auth and storage schemas are excluded. Run supabase db pull --schema auth,storage again to diff them.
+  - id: local-studio
+    name: Local studio
+    code: supabase db pull --local
+    response: |
+      Connecting to local database...
+      Setting up initial schema....
+      Creating custom roles supabase/roles.sql...
+      Applying migration 20240414044403_remote_schema.sql...
+      No schema changes found
+      The auth and storage schemas are excluded. Run supabase db pull --schema auth,storage again to diff them.
+      exit status 1
+  - id: custom-schemas
+    name: Custom schemas
+    code: supabase db pull --schema auth,storage
+    response: |
+      Connecting to remote database...
+      Setting up initial schema....
+      Creating custom roles supabase/roles.sql...
+      Applying migration 20240414044403_remote_schema.sql...
+      No schema changes found
+      Try rerunning the command with --debug to troubleshoot the error.
+      exit status 1
 supabase-db-push:
   - id: basic-usage
     name: Basic usage
diff --git a/go.mod b/go.mod
index 23695ec9..e96cfb09 100644
--- a/go.mod
+++ b/go.mod
@@ -13,8 +13,8 @@ require (
 	github.com/charmbracelet/lipgloss v0.10.0
 	github.com/containers/common v0.58.1
 	github.com/deepmap/oapi-codegen v1.16.2
-	github.com/docker/cli v26.0.0+incompatible
-	github.com/docker/docker v26.0.0+incompatible
+	github.com/docker/cli v26.0.1+incompatible
+	github.com/docker/docker v26.0.1+incompatible
 	github.com/docker/go-connections v0.5.0
 	github.com/docker/go-units v0.5.0
 	github.com/getsentry/sentry-go v0.27.0
@@ -46,10 +46,10 @@ require (
 	github.com/stripe/pg-schema-diff v0.6.0
 	github.com/withfig/autocomplete-tools/packages/cobra v1.2.0
 	github.com/zalando/go-keyring v0.2.4
-	golang.org/x/mod v0.16.0
-	golang.org/x/oauth2 v0.18.0
-	golang.org/x/term v0.18.0
-	google.golang.org/grpc v1.62.1
+	golang.org/x/mod v0.17.0
+	golang.org/x/oauth2 v0.19.0
+	golang.org/x/term v0.19.0
+	google.golang.org/grpc v1.63.2
 	gopkg.in/h2non/gock.v1 v1.1.2
 	gopkg.in/yaml.v3 v3.0.1
 	gotest.tools/gotestsum v1.11.0
@@ -156,7 +156,7 @@ require (
 	github.com/gofrs/flock v0.8.1 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
-	github.com/golang/protobuf v1.5.3 // indirect
+	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
 	github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e // indirect
 	github.com/golangci/misspell v0.4.1 // indirect
@@ -325,10 +325,9 @@ require (
 	golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f // indirect
 	golang.org/x/net v0.22.0 // indirect
 	golang.org/x/sync v0.6.0 // indirect
-	golang.org/x/sys v0.18.0 // indirect
+	golang.org/x/sys v0.19.0 // indirect
 	golang.org/x/text v0.14.0 // indirect
 	golang.org/x/tools v0.19.0 // indirect
-	google.golang.org/appengine v1.6.8 // indirect
 	google.golang.org/protobuf v1.33.0 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/warnings.v0 v0.1.2 // indirect
diff --git a/go.sum b/go.sum
index 2596ff7e..73ee0d3b 100644
--- a/go.sum
+++ b/go.sum
@@ -233,13 +233,13 @@ github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E
 github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
 github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk=
 github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE=
-github.com/docker/cli v26.0.0+incompatible h1:90BKrx1a1HKYpSnnBFR6AgDq/FqkHxwlUyzJVPxD30I=
-github.com/docker/cli v26.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/cli v26.0.1+incompatible h1:eZDuplk2jYqgUkNLDYwTBxqmY9cM3yHnmN6OIUEjL3U=
+github.com/docker/cli v26.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
 github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v26.0.0+incompatible h1:Ng2qi+gdKADUa/VM+6b6YaY2nlZhk/lVJiKR/2bMudU=
-github.com/docker/docker v26.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v26.0.1+incompatible h1:t39Hm6lpXuXtgkF0dm1t9a5HkbUfdGy6XbWexmGr+hA=
+github.com/docker/docker v26.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
 github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
 github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
@@ -418,8 +418,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
 github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
 github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e h1:ULcKCDV1LOZPFxGZaA6TlQbiM3J2GCPnkx/bGF6sX/g=
@@ -1141,8 +1141,8 @@ golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
-golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1196,8 +1196,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
 golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
-golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
+golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
+golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1281,8 +1281,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
+golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1294,8 +1294,8 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
 golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
 golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
-golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
-golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
+golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
+golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1304,7 +1304,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
 golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
@@ -1417,8 +1416,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
 google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
-google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -1448,11 +1445,11 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
 google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
-google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU=
-google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
+google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
+google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0=
+google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
 google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@@ -1466,8 +1463,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
 google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
 google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
-google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
+google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
+google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go
index 68832b07..800b4108 100644
--- a/internal/bootstrap/bootstrap.go
+++ b/internal/bootstrap/bootstrap.go
@@ -34,7 +34,7 @@ import (
 	"golang.org/x/term"
 )
 
-func Run(ctx context.Context, templateUrl string, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
+func Run(ctx context.Context, starter StarterTemplate, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
 	workdir := viper.GetString("WORKDIR")
 	if !filepath.IsAbs(workdir) {
 		workdir = filepath.Join(utils.CurrentDirAbs, workdir)
@@ -54,9 +54,9 @@ func Run(ctx context.Context, templateUrl string, fsys afero.Fs, options ...func
 		return err
 	}
 	// 0. Download starter template
-	if len(templateUrl) > 0 {
+	if len(starter.Url) > 0 {
 		client := GetGtihubClient(ctx)
-		if err := downloadSample(ctx, client, templateUrl, fsys); err != nil {
+		if err := downloadSample(ctx, client, starter.Url, fsys); err != nil {
 			return err
 		}
 	} else if err := initBlank.Run(fsys, nil, nil, utils.InitParams{Overwrite: true}); err != nil {
@@ -75,7 +75,10 @@ func Run(ctx context.Context, templateUrl string, fsys afero.Fs, options ...func
 		return err
 	}
 	// 2. Create project
-	params := api.CreateProjectBody{Name: filepath.Base(workdir)}
+	params := api.CreateProjectBody{
+		Name:        filepath.Base(workdir),
+		TemplateUrl: &starter.Url,
+	}
 	if err := create.Run(ctx, params, fsys); err != nil {
 		return err
 	}
@@ -115,15 +118,16 @@ func Run(ctx context.Context, templateUrl string, fsys afero.Fs, options ...func
 	}
 	policy.Reset()
 	if err := backoff.RetryNotify(func() error {
-		return push.Run(ctx, false, false, false, false, config, fsys)
+		return push.Run(ctx, false, false, true, true, config, fsys)
 	}, policy, newErrorCallback()); err != nil {
 		return err
 	}
-	utils.CmdSuggestion = suggestAppStart(utils.CurrentDirAbs)
+	// 7. TODO: deploy functions
+	utils.CmdSuggestion = suggestAppStart(utils.CurrentDirAbs, starter.Start)
 	return nil
 }
 
-func suggestAppStart(cwd string) string {
+func suggestAppStart(cwd, command string) string {
 	logger := utils.GetDebugLogger()
 	workdir, err := os.Getwd()
 	if err != nil {
@@ -137,7 +141,9 @@ func suggestAppStart(cwd string) string {
 	if len(workdir) > 0 && workdir != "." {
 		cmd = append(cmd, "cd "+workdir)
 	}
-	cmd = append(cmd, "npm ci", "npm run dev")
+	if len(command) > 0 {
+		cmd = append(cmd, command)
+	}
 	suggestion := "To start your app:"
 	for _, c := range cmd {
 		suggestion += fmt.Sprintf("\n  %s", utils.Aqua(c))
@@ -206,6 +212,8 @@ const (
 	POSTGRES_DATABASE             = "POSTGRES_DATABASE"
 	NEXT_PUBLIC_SUPABASE_ANON_KEY = "NEXT_PUBLIC_SUPABASE_ANON_KEY"
 	NEXT_PUBLIC_SUPABASE_URL      = "NEXT_PUBLIC_SUPABASE_URL"
+	EXPO_PUBLIC_SUPABASE_ANON_KEY = "EXPO_PUBLIC_SUPABASE_ANON_KEY"
+	EXPO_PUBLIC_SUPABASE_URL      = "EXPO_PUBLIC_SUPABASE_URL"
 )
 
 func writeDotEnv(keys []api.ApiKeyResponse, config pgconn.Config, fsys afero.Fs) error {
@@ -246,8 +254,12 @@ func writeDotEnv(keys []api.ApiKeyResponse, config pgconn.Config, fsys afero.Fs)
 		case POSTGRES_DATABASE:
 			initial[k] = config.Database
 		case NEXT_PUBLIC_SUPABASE_ANON_KEY:
+			fallthrough
+		case EXPO_PUBLIC_SUPABASE_ANON_KEY:
 			initial[k] = initial[SUPABASE_ANON_KEY]
 		case NEXT_PUBLIC_SUPABASE_URL:
+			fallthrough
+		case EXPO_PUBLIC_SUPABASE_URL:
 			initial[k] = initial[SUPABASE_URL]
 		default:
 			initial[k] = v
@@ -305,6 +317,7 @@ type StarterTemplate struct {
 	Name        string `json:"name"`
 	Description string `json:"description"`
 	Url         string `json:"url"`
+	Start       string `json:"start"`
 }
 
 func ListSamples(ctx context.Context, client *github.Client) ([]StarterTemplate, error) {
diff --git a/internal/db/pull/pull.go b/internal/db/pull/pull.go
index 021c0eb5..ef76747a 100644
--- a/internal/db/pull/pull.go
+++ b/internal/db/pull/pull.go
@@ -21,8 +21,8 @@ import (
 )
 
 var (
-	errMissing       = errors.New("no migrations found")
-	errInSync        = errors.New("no schema changes found")
+	errMissing       = errors.New("No migrations found")
+	errInSync        = errors.New("No schema changes found")
 	errConflict      = errors.Errorf("The remote database's migration history does not match local files in %s directory.", utils.MigrationsDir)
 	suggestExtraPull = fmt.Sprintf(
 		"The %s and %s schemas are excluded. Run %s again to diff them.",
@@ -64,18 +64,18 @@ func Run(ctx context.Context, schema []string, config pgconn.Config, name string
 
 func run(p utils.Program, ctx context.Context, schema []string, path string, conn *pgx.Conn, fsys afero.Fs) error {
 	config := conn.Config().Config
-	defaultSchema := len(schema) == 0
 	// 1. Assert `supabase/migrations` and `schema_migrations` are in sync.
 	if err := assertRemoteInSync(ctx, conn, fsys); errors.Is(err, errMissing) {
-		if !defaultSchema {
+		// Not passing down schemas to avoid pulling in managed schemas
+		if err = dumpRemoteSchema(p, ctx, path, config, fsys); err == nil {
 			utils.CmdSuggestion = suggestExtraPull
 		}
-		// Not passing down schemas to avoid pulling in managed schemas
-		return dumpRemoteSchema(p, ctx, path, config, fsys)
+		return err
 	} else if err != nil {
 		return err
 	}
 	// 2. Fetch remote schema changes
+	defaultSchema := len(schema) == 0
 	if defaultSchema {
 		var err error
 		schema, err = diff.LoadUserSchemas(ctx, conn)
@@ -84,7 +84,7 @@ func run(p utils.Program, ctx context.Context, schema []string, path string, con
 		}
 	}
 	err := diffRemoteSchema(p, ctx, schema, path, config, fsys)
-	if defaultSchema && (err == nil || errors.Is(errInSync, err)) {
+	if defaultSchema && (err == nil || errors.Is(err, errInSync)) {
 		utils.CmdSuggestion = suggestExtraPull
 	}
 	return err
diff --git a/internal/db/remote/commit/commit.go b/internal/db/remote/commit/commit.go
index 2d518113..c58a7a61 100644
--- a/internal/db/remote/commit/commit.go
+++ b/internal/db/remote/commit/commit.go
@@ -83,7 +83,7 @@ func fetchRemote(p utils.Program, ctx context.Context, schema []string, timestam
 		return err
 	}
 	if len(output) == 0 {
-		return errors.New("no schema changes found")
+		return errors.New("No schema changes found")
 	}
 	return afero.WriteFile(fsys, path, []byte(output), 0644)
 }
diff --git a/internal/db/reset/reset.go b/internal/db/reset/reset.go
index 27ccd3d9..24aaab2c 100644
--- a/internal/db/reset/reset.go
+++ b/internal/db/reset/reset.go
@@ -289,7 +289,7 @@ func resetRemote(ctx context.Context, version string, config pgconn.Config, fsys
 }
 
 func ListSchemas(ctx context.Context, conn *pgx.Conn, exclude ...string) ([]string, error) {
-	exclude = likeEscapeSchema(exclude)
+	exclude = LikeEscapeSchema(exclude)
 	if len(exclude) == 0 {
 		exclude = append(exclude, "")
 	}
@@ -300,7 +300,7 @@ func ListSchemas(ctx context.Context, conn *pgx.Conn, exclude ...string) ([]stri
 	return pgxv5.CollectStrings(rows)
 }
 
-func likeEscapeSchema(schemas []string) (result []string) {
+func LikeEscapeSchema(schemas []string) (result []string) {
 	// Treat _ as literal, * as any character
 	replacer := strings.NewReplacer("_", `\_`, "*", "%")
 	for _, sch := range schemas {
diff --git a/internal/functions/deploy/deploy.go b/internal/functions/deploy/deploy.go
index 82028282..56e3a067 100644
--- a/internal/functions/deploy/deploy.go
+++ b/internal/functions/deploy/deploy.go
@@ -56,6 +56,14 @@ func Run(ctx context.Context, slugs []string, projectRef string, noVerifyJWT *bo
 	return deployAll(ctx, slugs, projectRef, importMapPath, noVerifyJWT, fsys)
 }
 
+func RunDefault(ctx context.Context, projectRef string, fsys afero.Fs) error {
+	slugs, err := getFunctionSlugs(fsys)
+	if len(slugs) == 0 {
+		return err
+	}
+	return deployAll(ctx, slugs, projectRef, "", nil, fsys)
+}
+
 func getFunctionSlugs(fsys afero.Fs) ([]string, error) {
 	pattern := filepath.Join(utils.FunctionsDir, "*", "index.ts")
 	paths, err := afero.Glob(fsys, pattern)
@@ -78,7 +86,7 @@ func bundleFunction(ctx context.Context, slug, dockerEntrypointPath, importMapPa
 		return nil, errors.Errorf("failed to get working directory: %w", err)
 	}
 
-	// create temp directory to store generated eszip
+	// Create temp directory to store generated eszip
 	hostOutputDir := filepath.Join(utils.TempDir, fmt.Sprintf(".output_%s", slug))
 	// BitBucket pipelines require docker bind mounts to be world writable
 	if err := fsys.MkdirAll(hostOutputDir, 0777); err != nil {
@@ -235,24 +243,24 @@ func deployOne(ctx context.Context, slug, projectRef, importMapPath string, noVe
 	// 3. Deploy new Function.
 	functionSize := units.HumanSize(float64(functionBody.Len()))
 	fmt.Println("Deploying " + utils.Bold(slug) + " (script size: " + utils.Bold(functionSize) + ")")
-	return deployFunction(
-		ctx,
-		projectRef,
-		slug,
-		"file://"+dockerEntrypointPath,
-		"file://"+dockerImportMapPath,
-		!*noVerifyJWT,
-		functionBody,
-	)
+	policy := backoff.WithContext(backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 3), ctx)
+	return backoff.Retry(func() error {
+		return deployFunction(
+			ctx,
+			projectRef,
+			slug,
+			"file://"+dockerEntrypointPath,
+			"file://"+dockerImportMapPath,
+			!*noVerifyJWT,
+			functionBody,
+		)
+	}, policy)
 }
 
 func deployAll(ctx context.Context, slugs []string, projectRef, importMapPath string, noVerifyJWT *bool, fsys afero.Fs) error {
 	// TODO: api has a race condition that prevents deploying in parallel
 	for _, slug := range slugs {
-		policy := backoff.WithContext(backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 3), ctx)
-		if err := backoff.Retry(func() error {
-			return deployOne(ctx, slug, projectRef, importMapPath, noVerifyJWT, fsys)
-		}, policy); err != nil {
+		if err := deployOne(ctx, slug, projectRef, importMapPath, noVerifyJWT, fsys); err != nil {
 			return err
 		}
 	}
diff --git a/internal/functions/download/download.go b/internal/functions/download/download.go
index 4d6be9fd..8bf55155 100644
--- a/internal/functions/download/download.go
+++ b/internal/functions/download/download.go
@@ -129,50 +129,56 @@ func Run(ctx context.Context, slug string, projectRef string, useLegacyBundle bo
 		}
 	}()
 	// Extract eszip to functions directory
-	err = extractOne(ctx, eszipPath)
+	err = extractOne(ctx, slug, eszipPath)
 	if err != nil {
 		utils.CmdSuggestion += suggestLegacyBundle(slug)
 	}
 	return err
 }
 
-func downloadOne(ctx context.Context, slug string, projectRef string, fsys afero.Fs) (string, error) {
+func downloadOne(ctx context.Context, slug, projectRef string, fsys afero.Fs) (string, error) {
 	fmt.Println("Downloading " + utils.Bold(slug))
-	resp, err := utils.GetSupabase().GetFunctionBodyWithResponse(ctx, projectRef, slug)
+	resp, err := utils.GetSupabase().GetFunctionBody(ctx, projectRef, slug)
 	if err != nil {
 		return "", errors.Errorf("failed to get function body: %w", err)
 	}
-	if resp.StatusCode() != http.StatusOK {
-		return "", errors.New("Unexpected error downloading Function: " + string(resp.Body))
+	defer resp.Body.Close()
+	if resp.StatusCode != http.StatusOK {
+		body, err := io.ReadAll(resp.Body)
+		if err != nil {
+			return "", errors.Errorf("Error status %d: unexpected error downloading Function", resp.StatusCode)
+		}
+		return "", errors.Errorf("Error status %d: %s", resp.StatusCode, string(body))
 	}
-
 	// Create temp file to store downloaded eszip
-	eszipFile, err := afero.TempFile(fsys, "", slug)
-	if err != nil {
-		return "", errors.Errorf("failed to create temporary file: %w", err)
+	eszipPath := filepath.Join(utils.TempDir, fmt.Sprintf("output_%s.eszip", slug))
+	if err := utils.MkdirIfNotExistFS(fsys, utils.TempDir); err != nil {
+		return "", err
 	}
-	defer eszipFile.Close()
-
-	body := bytes.NewReader(resp.Body)
-	if _, err = io.Copy(eszipFile, body); err != nil {
+	if err := afero.WriteReader(fsys, eszipPath, resp.Body); err != nil {
 		return "", errors.Errorf("failed to download file: %w", err)
 	}
-	return eszipFile.Name(), nil
+	return eszipPath, nil
 }
 
-func extractOne(ctx context.Context, hostEszipPath string) error {
-	hostFuncDirPath, err := filepath.Abs(utils.FunctionsDir)
+func extractOne(ctx context.Context, slug, eszipPath string) error {
+	hostFuncDirPath, err := filepath.Abs(filepath.Join(utils.FunctionsDir, slug))
 	if err != nil {
 		return errors.Errorf("failed to resolve absolute path: %w", err)
 	}
 
+	hostEszipPath, err := filepath.Abs(eszipPath)
+	if err != nil {
+		return errors.Errorf("failed to resolve eszip path: %w", err)
+	}
 	dockerEszipPath := path.Join(dockerEszipDir, filepath.Base(hostEszipPath))
+
 	binds := []string{
 		// Reuse deno cache directory, ie. DENO_DIR, between container restarts
 		// https://denolib.gitbook.io/guide/advanced/deno_dir-code-fetch-and-cache
 		utils.EdgeRuntimeId + ":/root/.cache/deno:rw,z",
 		hostEszipPath + ":" + dockerEszipPath + ":ro,z",
-		hostFuncDirPath + ":" + utils.DockerFuncDirPath + ":rw,z",
+		hostFuncDirPath + ":" + utils.DockerDenoDir + ":rw,z",
 	}
 
 	return utils.DockerRunOnceWithConfig(
diff --git a/internal/inspect/bloat/bloat.go b/internal/inspect/bloat/bloat.go
index d8040863..6bb2c57c 100644
--- a/internal/inspect/bloat/bloat.go
+++ b/internal/inspect/bloat/bloat.go
@@ -8,73 +8,13 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/db/reset"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-WITH constants AS (
-  SELECT current_setting('block_size')::numeric AS bs, 23 AS hdr, 4 AS ma
-), bloat_info AS (
-  SELECT
-    ma,bs,schemaname,tablename,
-    (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
-    (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
-  FROM (
-    SELECT
-      schemaname, tablename, hdr, ma, bs,
-      SUM((1-null_frac)*avg_width) AS datawidth,
-      MAX(null_frac) AS maxfracsum,
-      hdr+(
-        SELECT 1+count(*)/8
-        FROM pg_stats s2
-        WHERE null_frac<>0 AND s2.schemaname = s.schemaname AND s2.tablename = s.tablename
-      ) AS nullhdr
-    FROM pg_stats s, constants
-    GROUP BY 1,2,3,4,5
-  ) AS foo
-), table_bloat AS (
-  SELECT
-    schemaname, tablename, cc.relpages, bs,
-    CEIL((cc.reltuples*((datahdr+ma-
-      (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)) AS otta
-  FROM bloat_info
-  JOIN pg_class cc ON cc.relname = bloat_info.tablename
-  JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = bloat_info.schemaname AND nn.nspname <> 'information_schema'
-), index_bloat AS (
-  SELECT
-    schemaname, tablename, bs,
-    COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
-    COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
-  FROM bloat_info
-  JOIN pg_class cc ON cc.relname = bloat_info.tablename
-  JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = bloat_info.schemaname AND nn.nspname <> 'information_schema'
-  JOIN pg_index i ON indrelid = cc.oid
-  JOIN pg_class c2 ON c2.oid = i.indexrelid
-)
-SELECT
-  type, schemaname, object_name, bloat, pg_size_pretty(raw_waste) as waste
-FROM
-(SELECT
-  'table' as type,
-  schemaname,
-  tablename as object_name,
-  ROUND(CASE WHEN otta=0 THEN 0.0 ELSE table_bloat.relpages/otta::numeric END,1) AS bloat,
-  CASE WHEN relpages < otta THEN '0' ELSE (bs*(table_bloat.relpages-otta)::bigint)::bigint END AS raw_waste
-FROM
-  table_bloat
-    UNION
-SELECT
-  'index' as type,
-  schemaname,
-  tablename || '::' || iname as object_name,
-  ROUND(CASE WHEN iotta=0 OR ipages=0 THEN 0.0 ELSE ipages/iotta::numeric END,1) AS bloat,
-  CASE WHEN ipages < iotta THEN '0' ELSE (bs*(ipages-iotta))::bigint END AS raw_waste
-FROM
-  index_bloat) bloat_summary
-ORDER BY raw_waste DESC, bloat DESC`
-
 type Result struct {
 	Type        string
 	Schemaname  string
@@ -88,7 +28,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.BLOAT_QUERY, reset.LikeEscapeSchema(utils.InternalSchemas))
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
diff --git a/internal/inspect/blocking/blocking.go b/internal/inspect/blocking/blocking.go
index 3d418bf6..2367cf12 100644
--- a/internal/inspect/blocking/blocking.go
+++ b/internal/inspect/blocking/blocking.go
@@ -9,35 +9,17 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-// Ref: https://github.com/heroku/heroku-pg-extras/blob/main/commands/blocking.js#L7
-const QUERY = `
-SELECT
-	bl.pid AS blocked_pid,
-	ka.query AS blocking_statement,
-	now() - ka.query_start AS blocking_duration,
-	kl.pid AS blocking_pid,
-	a.query AS blocked_statement,
-	now() - a.query_start AS blocked_duration
-FROM pg_catalog.pg_locks bl
-JOIN pg_catalog.pg_stat_activity a
-	ON bl.pid = a.pid
-JOIN pg_catalog.pg_locks kl
-JOIN pg_catalog.pg_stat_activity ka
-	ON kl.pid = ka.pid
-	ON bl.transactionid = kl.transactionid AND bl.pid != kl.pid
-WHERE NOT bl.granted
-`
-
 type Result struct {
-	Blocked_pid        string
+	Blocked_pid        int
 	Blocking_statement string
 	Blocking_duration  string
-	Blocking_pid       string
+	Blocking_pid       int
 	Blocked_statement  string
 	Blocked_duration   string
 }
@@ -47,7 +29,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.BLOCKING_QUERY)
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
@@ -67,7 +49,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 		re = regexp.MustCompile(`\|`)
 		blocking_statement = re.ReplaceAllString(blocking_statement, `\|`)
 		blocked_statement = re.ReplaceAllString(blocked_statement, `\|`)
-		table += fmt.Sprintf("|`%v`|`%v`|`%v`|`%v`|%s|`%v`|\n", r.Blocked_pid, blocking_statement, r.Blocking_duration, r.Blocking_pid, blocked_statement, r.Blocked_duration)
+		table += fmt.Sprintf("|`%d`|`%s`|`%s`|`%d`|%s|`%s`|\n", r.Blocked_pid, blocking_statement, r.Blocking_duration, r.Blocking_pid, blocked_statement, r.Blocked_duration)
 	}
 	return list.RenderTable(table)
 }
diff --git a/internal/inspect/cache/cache.go b/internal/inspect/cache/cache.go
index 88f3c65a..eb16a7bb 100644
--- a/internal/inspect/cache/cache.go
+++ b/internal/inspect/cache/cache.go
@@ -8,24 +8,12 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-// Ref: https://github.com/heroku/heroku-pg-extras/blob/main/commands/cache_hit.js#L7
-const QUERY = `
-SELECT
-  'index hit rate' AS name,
-  (sum(idx_blks_hit)) / nullif(sum(idx_blks_hit + idx_blks_read),0) AS ratio
-FROM pg_statio_user_indexes
-UNION ALL
-SELECT
- 'table hit rate' AS name,
-  sum(heap_blks_hit) / nullif(sum(heap_blks_hit) + sum(heap_blks_read),0) AS ratio
-FROM pg_statio_user_tables;
-`
-
 type Result struct {
 	Name  string
 	Ratio float64
@@ -36,7 +24,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.CACHE_QUERY)
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
@@ -45,9 +33,19 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 		return err
 	}
 	// TODO: implement a markdown table marshaller
-	table := "|Name|Ratio|\n|-|-|\n"
+	table := "|Name|Ratio|OK?|Explanation|\n|-|-|-|-|\n"
 	for _, r := range result {
-		table += fmt.Sprintf("|`%s`|`%.6f`|\n", r.Name, r.Ratio)
+		ok := "Yup!"
+		if r.Ratio < 0.94 {
+			ok = "Maybe not..."
+		}
+		var explanation string
+		if r.Name == "index hit rate" {
+			explanation = "This is the ratio of index hits to index scans. If this ratio is low, it means that the database is not using indexes effectively. Check the `index-usage` command for more info."
+		} else if r.Name == "table hit rate" {
+			explanation = "This is the ratio of table hits to table scans. If this ratio is low, it means that your queries are not finding the data effectively. Check your query performance and it might be worth increasing your compute."
+		}
+		table += fmt.Sprintf("|`%s`|`%.6f`|`%s`|`%s`|\n", r.Name, r.Ratio, ok, explanation)
 	}
 	return list.RenderTable(table)
 }
diff --git a/internal/inspect/calls/calls.go b/internal/inspect/calls/calls.go
index faf289ee..02808cb0 100644
--- a/internal/inspect/calls/calls.go
+++ b/internal/inspect/calls/calls.go
@@ -9,23 +9,12 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT
-	query,
-	interval '1 millisecond' * total_exec_time AS total_exec_time,
-	to_char((total_exec_time/sum(total_exec_time) OVER()) * 100, 'FM90D0') || '%'  AS prop_exec_time,
-	to_char(calls, 'FM999G999G990') AS ncalls,
-	interval '1 millisecond' * (blk_read_time + blk_write_time) AS sync_io_time
-FROM pg_stat_statements	
-ORDER BY calls DESC
-LIMIT 10
-`
-
 type Result struct {
 	Total_exec_time string
 	Prop_exec_time  string
@@ -39,7 +28,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.CALLS_QUERY)
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
diff --git a/internal/inspect/index_sizes/index_sizes.go b/internal/inspect/index_sizes/index_sizes.go
index 2d5848bc..37e6f273 100644
--- a/internal/inspect/index_sizes/index_sizes.go
+++ b/internal/inspect/index_sizes/index_sizes.go
@@ -8,22 +8,13 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/db/reset"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT c.relname AS name,
-  pg_size_pretty(sum(c.relpages::bigint*8192)::bigint) AS size
-FROM pg_class c
-LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
-WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
-AND n.nspname !~ '^pg_toast'
-AND c.relkind='i'
-GROUP BY c.relname
-ORDER BY sum(c.relpages) DESC;`
-
 type Result struct {
 	Name string
 	Size string
@@ -34,7 +25,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.INDEX_SIZES_QUERY, reset.LikeEscapeSchema(utils.InternalSchemas))
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
diff --git a/internal/inspect/index_usage/index_usage.go b/internal/inspect/index_usage/index_usage.go
index cd304609..c34d7deb 100644
--- a/internal/inspect/index_usage/index_usage.go
+++ b/internal/inspect/index_usage/index_usage.go
@@ -8,34 +8,17 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/db/reset"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT relname,
-  CASE
-    WHEN idx_scan IS NULL THEN 'Insufficient data'
-    WHEN idx_scan = 0 THEN 'Insufficient data'
-    ELSE (100 * idx_scan / (seq_scan + idx_scan))::text
-  END percent_of_times_index_used,
-  n_live_tup rows_in_table
-FROM
-  pg_stat_user_tables
-ORDER BY
-  CASE
-    WHEN idx_scan is null then 1
-    WHEN idx_scan = 0 then 1
-    ELSE 0
-  END,
-  n_live_tup DESC;
-`
-
 type Result struct {
-	Relname                     string
+	Name                        string
 	Percent_of_times_index_used string
-	Rows_in_table               string
+	Rows_in_table               int64
 }
 
 func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
@@ -43,7 +26,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.INDEX_USAGE_QUERY, reset.LikeEscapeSchema(utils.InternalSchemas))
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
@@ -54,7 +37,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	// TODO: implement a markdown table marshaller
 	table := "|Table name|Percentage of times index used|Rows in table|\n|-|-|-|\n"
 	for _, r := range result {
-		table += fmt.Sprintf("|`%s`|`%v`|`%v`|\n", r.Relname, r.Percent_of_times_index_used, r.Rows_in_table)
+		table += fmt.Sprintf("|`%s`|`%s`|`%d`|\n", r.Name, r.Percent_of_times_index_used, r.Rows_in_table)
 	}
 	return list.RenderTable(table)
 }
diff --git a/internal/inspect/locks/locks.go b/internal/inspect/locks/locks.go
index 0d3eb5cd..efeb82ae 100644
--- a/internal/inspect/locks/locks.go
+++ b/internal/inspect/locks/locks.go
@@ -9,31 +9,17 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT
-	pg_stat_activity.pid,
-	COALESCE(pg_class.relname, 'null') AS relname,
-	COALESCE(pg_locks.transactionid, 'null') AS transactionid,
-	pg_locks.granted,
-	pg_stat_activity.query,
-	age(now(),pg_stat_activity.query_start) AS age
-FROM pg_stat_activity, pg_locks LEFT OUTER JOIN pg_class ON (pg_locks.relation = pg_class.oid)
-WHERE pg_stat_activity.query <> '<insufficient privilege>'
-AND pg_locks.pid=pg_stat_activity.pid
-AND pg_locks.mode = 'ExclusiveLock'
-ORDER BY query_start;
-`
-
 type Result struct {
-	Pid           string
+	Pid           int
 	Relname       string
 	Transactionid string
-	Granted       string
+	Granted       bool
 	Query         string
 	Age           string
 }
@@ -43,7 +29,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.LOCKS_QUERY)
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
@@ -61,7 +47,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 		// escape pipes in query
 		re = regexp.MustCompile(`\|`)
 		query = re.ReplaceAllString(query, `\|`)
-		table += fmt.Sprintf("|`%v`|`%v`|`%v`|`%v`|%s|`%v`|\n", r.Pid, r.Relname, r.Transactionid, r.Granted, query, r.Age)
+		table += fmt.Sprintf("|`%d`|`%s`|`%s`|`%t`|%s|`%s`|\n", r.Pid, r.Relname, r.Transactionid, r.Granted, query, r.Age)
 	}
 	return list.RenderTable(table)
 }
diff --git a/internal/inspect/long_running_queries/long_running_queries.go b/internal/inspect/long_running_queries/long_running_queries.go
index 9b18f527..e091515d 100644
--- a/internal/inspect/long_running_queries/long_running_queries.go
+++ b/internal/inspect/long_running_queries/long_running_queries.go
@@ -8,27 +8,14 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT
-  pid,
-  now() - pg_stat_activity.query_start AS duration,
-  query AS query
-FROM
-  pg_stat_activity
-WHERE
-  pg_stat_activity.query <> ''::text
-  AND state <> 'idle'
-  AND now() - pg_stat_activity.query_start > interval '5 minutes'
-ORDER BY
-  now() - pg_stat_activity.query_start DESC;`
-
 type Result struct {
-	Pid      string
+	Pid      int
 	Duration string
 	Query    string
 }
@@ -38,7 +25,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.LONG_RUNNING_QUERY)
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
@@ -49,7 +36,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 
 	table := "|pid|Duration|Query|\n|-|-|-|\n"
 	for _, r := range result {
-		table += fmt.Sprintf("|`%s`|`%s`|`%s`|\n", r.Pid, r.Duration, r.Query)
+		table += fmt.Sprintf("|`%d`|`%s`|`%s`|\n", r.Pid, r.Duration, r.Query)
 	}
 	return list.RenderTable(table)
 }
diff --git a/internal/inspect/outliers/outliers.go b/internal/inspect/outliers/outliers.go
index 33307045..d19a691e 100644
--- a/internal/inspect/outliers/outliers.go
+++ b/internal/inspect/outliers/outliers.go
@@ -9,23 +9,12 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT
-	interval '1 millisecond' * total_exec_time AS total_exec_time,
-	to_char((total_exec_time/sum(total_exec_time) OVER()) * 100, 'FM90D0') || '%'  AS prop_exec_time,
-	to_char(calls, 'FM999G999G999G990') AS ncalls,
-	interval '1 millisecond' * (blk_read_time + blk_write_time) AS sync_io_time,
-	query
-FROM pg_stat_statements WHERE userid = (SELECT usesysid FROM pg_user WHERE usename = current_user LIMIT 1)
-ORDER BY total_exec_time DESC
-LIMIT 10
-`
-
 type Result struct {
 	Total_exec_time string
 	Prop_exec_time  string
@@ -39,7 +28,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.OUTLIERS_QUERY)
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
diff --git a/internal/inspect/queries.go b/internal/inspect/queries.go
new file mode 100644
index 00000000..42139729
--- /dev/null
+++ b/internal/inspect/queries.go
@@ -0,0 +1,305 @@
+package inspect
+
+const BLOAT_QUERY = `WITH constants AS (
+  SELECT current_setting('block_size')::numeric AS bs, 23 AS hdr, 4 AS ma
+), bloat_info AS (
+  SELECT
+    ma,bs,schemaname,tablename,
+    (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
+    (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
+  FROM (
+    SELECT
+      schemaname, tablename, hdr, ma, bs,
+      SUM((1-null_frac)*avg_width) AS datawidth,
+      MAX(null_frac) AS maxfracsum,
+      hdr+(
+        SELECT 1+count(*)/8
+        FROM pg_stats s2
+        WHERE null_frac<>0 AND s2.schemaname = s.schemaname AND s2.tablename = s.tablename
+      ) AS nullhdr
+    FROM pg_stats s, constants
+    GROUP BY 1,2,3,4,5
+  ) AS foo
+), table_bloat AS (
+  SELECT
+    schemaname, tablename, cc.relpages, bs,
+    CEIL((cc.reltuples*((datahdr+ma-
+      (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)) AS otta
+  FROM bloat_info
+  JOIN pg_class cc ON cc.relname = bloat_info.tablename
+  JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = bloat_info.schemaname AND nn.nspname <> 'information_schema'
+), index_bloat AS (
+  SELECT
+    schemaname, tablename, bs,
+    COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
+    COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
+  FROM bloat_info
+  JOIN pg_class cc ON cc.relname = bloat_info.tablename
+  JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = bloat_info.schemaname AND nn.nspname <> 'information_schema'
+  JOIN pg_index i ON indrelid = cc.oid
+  JOIN pg_class c2 ON c2.oid = i.indexrelid
+)
+SELECT
+  type, schemaname, object_name, bloat, pg_size_pretty(raw_waste) as waste
+FROM
+(SELECT
+  'table' as type,
+  schemaname,
+  tablename as object_name,
+  ROUND(CASE WHEN otta=0 THEN 0.0 ELSE table_bloat.relpages/otta::numeric END,1) AS bloat,
+  CASE WHEN relpages < otta THEN '0' ELSE (bs*(table_bloat.relpages-otta)::bigint)::bigint END AS raw_waste
+FROM
+  table_bloat
+    UNION
+SELECT
+  'index' as type,
+  schemaname,
+  tablename || '::' || iname as object_name,
+  ROUND(CASE WHEN iotta=0 OR ipages=0 THEN 0.0 ELSE ipages/iotta::numeric END,1) AS bloat,
+  CASE WHEN ipages < iotta THEN '0' ELSE (bs*(ipages-iotta))::bigint END AS raw_waste
+FROM
+  index_bloat) bloat_summary
+WHERE NOT schemaname LIKE ANY($1)
+ORDER BY raw_waste DESC, bloat DESC`
+
+// Ref: https://github.com/heroku/heroku-pg-extras/blob/main/commands/blocking.js#L7
+const BLOCKING_QUERY = `SELECT
+  bl.pid AS blocked_pid,
+  ka.query AS blocking_statement,
+  age(now(), ka.query_start)::text AS blocking_duration,
+  kl.pid AS blocking_pid,
+  a.query AS blocked_statement,
+  age(now(), a.query_start)::text AS blocked_duration
+FROM pg_catalog.pg_locks bl
+JOIN pg_catalog.pg_stat_activity a
+  ON bl.pid = a.pid
+JOIN pg_catalog.pg_locks kl
+JOIN pg_catalog.pg_stat_activity ka
+  ON kl.pid = ka.pid
+  ON bl.transactionid = kl.transactionid AND bl.pid != kl.pid
+WHERE NOT bl.granted`
+
+// Ref: https://github.com/heroku/heroku-pg-extras/blob/main/commands/cache_hit.js#L7
+const CACHE_QUERY = `SELECT
+  'index hit rate' AS name,
+  (sum(idx_blks_hit)) / nullif(sum(idx_blks_hit + idx_blks_read),0) AS ratio
+FROM pg_statio_user_indexes
+UNION ALL
+SELECT
+  'table hit rate' AS name,
+  sum(heap_blks_hit) / nullif(sum(heap_blks_hit) + sum(heap_blks_read),0) AS ratio
+FROM pg_statio_user_tables;`
+
+const CALLS_QUERY = `SELECT
+  query,
+  (interval '1 millisecond' * total_exec_time)::text AS total_exec_time,
+  to_char((total_exec_time/sum(total_exec_time) OVER()) * 100, 'FM90D0') || '%'  AS prop_exec_time,
+  to_char(calls, 'FM999G999G990') AS ncalls,
+  (interval '1 millisecond' * (blk_read_time + blk_write_time))::text AS sync_io_time
+FROM pg_stat_statements
+ORDER BY calls DESC
+LIMIT 10`
+
+const INDEX_SIZES_QUERY = `SELECT
+  n.nspname || '.' || c.relname AS name,
+  pg_size_pretty(sum(c.relpages::bigint*8192)::bigint) AS size
+FROM pg_class c
+LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
+WHERE NOT n.nspname LIKE ANY($1)
+AND c.relkind = 'i'
+GROUP BY n.nspname, c.relname
+ORDER BY sum(c.relpages) DESC`
+
+const INDEX_USAGE_QUERY = `SELECT
+  schemaname || '.' || relname AS name,
+  CASE
+    WHEN idx_scan IS NULL THEN 'Insufficient data'
+    WHEN idx_scan = 0 THEN 'Insufficient data'
+    ELSE ROUND(100.0 * idx_scan / (seq_scan + idx_scan), 1) || '%'
+  END percent_of_times_index_used,
+  n_live_tup rows_in_table
+FROM pg_stat_user_tables
+WHERE NOT schemaname LIKE ANY($1)
+ORDER BY
+  CASE
+    WHEN idx_scan is null then 1
+    WHEN idx_scan = 0 then 1
+    ELSE 0
+  END,
+  n_live_tup DESC`
+
+const LOCKS_QUERY = `SELECT
+  pg_stat_activity.pid,
+  COALESCE(pg_class.relname, 'null') AS relname,
+  COALESCE(pg_locks.transactionid, 'null') AS transactionid,
+  pg_locks.granted,
+  pg_stat_activity.query,
+  age(now(), pg_stat_activity.query_start)::text AS age
+FROM pg_stat_activity, pg_locks LEFT OUTER JOIN pg_class ON (pg_locks.relation = pg_class.oid)
+WHERE pg_stat_activity.query <> '<insufficient privilege>'
+AND pg_locks.pid = pg_stat_activity.pid
+AND pg_locks.mode = 'ExclusiveLock'
+ORDER BY query_start`
+
+const LONG_RUNNING_QUERY = `SELECT
+  pid,
+  age(now(), pg_stat_activity.query_start)::text AS duration,
+  query AS query
+FROM
+  pg_stat_activity
+WHERE
+  pg_stat_activity.query <> ''::text
+  AND state <> 'idle'
+  AND age(now(), pg_stat_activity.query_start) > interval '5 minutes'
+ORDER BY
+  age(now(), pg_stat_activity.query_start) DESC`
+
+const OUTLIERS_QUERY = `SELECT
+  (interval '1 millisecond' * total_exec_time)::text AS total_exec_time,
+  to_char((total_exec_time/sum(total_exec_time) OVER()) * 100, 'FM90D0') || '%'  AS prop_exec_time,
+  to_char(calls, 'FM999G999G999G990') AS ncalls,
+  (interval '1 millisecond' * (blk_read_time + blk_write_time))::text AS sync_io_time,
+  query
+FROM pg_stat_statements WHERE userid = (SELECT usesysid FROM pg_user WHERE usename = current_user LIMIT 1)
+ORDER BY total_exec_time DESC
+LIMIT 10`
+
+const REPLICATION_SLOTS_QUERY = `SELECT
+  s.slot_name,
+  s.active,
+  COALESCE(r.state, 'N/A') as state,
+  CASE WHEN r.client_addr IS NULL
+    THEN 'N/A'
+    ELSE r.client_addr::text
+  END replication_client_address,
+  GREATEST(0, ROUND((redo_lsn-restart_lsn)/1024/1024/1024, 2)) as replication_lag_gb
+FROM pg_control_checkpoint(), pg_replication_slots s
+LEFT JOIN pg_stat_replication r ON (r.pid = s.active_pid)`
+
+const ROLE_CONNECTIONS_QUERY = `SELECT
+  rolname,
+  (
+    SELECT
+      count(*)
+    FROM
+      pg_stat_activity
+    WHERE
+      pg_roles.rolname = pg_stat_activity.usename
+  ) AS active_connections,
+  CASE WHEN rolconnlimit = -1
+    THEN current_setting('max_connections')::int8
+    ELSE rolconnlimit
+  END AS connection_limit
+FROM pg_roles
+ORDER BY 2 DESC`
+
+const SEQ_SCANS_QUERY = `SELECT
+  schemaname || '.' || relname AS name,
+  seq_scan as count
+FROM pg_stat_user_tables
+WHERE NOT schemaname LIKE ANY($1)
+ORDER BY seq_scan DESC`
+
+const TABLE_INDEX_SIZES_QUERY = `SELECT
+  n.nspname || '.' || c.relname AS table,
+  pg_size_pretty(pg_indexes_size(c.oid)) AS index_size
+FROM pg_class c
+LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
+WHERE NOT n.nspname LIKE ANY($1)
+AND c.relkind = 'r'
+ORDER BY pg_indexes_size(c.oid) DESC`
+
+const TABLE_RECORD_COUNTS_QUERY = `SELECT
+  schemaname AS schema,
+  relname AS name,
+  n_live_tup AS estimated_count
+FROM pg_stat_user_tables
+WHERE NOT schemaname LIKE ANY($1)
+ORDER BY n_live_tup DESC`
+
+const TABLE_SIZES_QUERY = `SELECT
+  n.nspname AS schema,
+  c.relname AS name,
+  pg_size_pretty(pg_table_size(c.oid)) AS size
+FROM pg_class c
+LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
+WHERE NOT n.nspname LIKE ANY($1)
+AND c.relkind = 'r'
+ORDER BY pg_table_size(c.oid) DESC`
+
+const TOTAL_INDEX_SIZE_QUERY = `SELECT
+  pg_size_pretty(sum(c.relpages::bigint*8192)::bigint) AS size
+FROM pg_class c
+LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
+WHERE NOT n.nspname LIKE ANY($1)
+AND c.relkind = 'i'`
+
+const TOTAL_TABLE_SIZES_QUERY = `SELECT
+  n.nspname AS schema,
+  c.relname AS name,
+  pg_size_pretty(pg_total_relation_size(c.oid)) AS size
+FROM pg_class c
+LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
+WHERE NOT n.nspname LIKE ANY($1)
+AND c.relkind = 'r'
+ORDER BY pg_total_relation_size(c.oid) DESC`
+
+const UNUSED_INDEXES_QUERY = `SELECT
+  schemaname || '.' || relname AS table,
+  indexrelname AS index,
+  pg_size_pretty(pg_relation_size(i.indexrelid)) AS index_size,
+  idx_scan as index_scans
+FROM pg_stat_user_indexes ui
+JOIN pg_index i ON ui.indexrelid = i.indexrelid
+WHERE
+  NOT indisunique AND idx_scan < 50 AND pg_relation_size(relid) > 5 * 8192
+  AND NOT schemaname LIKE ANY($1)
+ORDER BY
+  pg_relation_size(i.indexrelid) / nullif(idx_scan, 0) DESC NULLS FIRST,
+  pg_relation_size(i.indexrelid) DESC`
+
+const VACUUM_STATS_QUERY = `WITH table_opts AS (
+  SELECT
+    pg_class.oid, relname, nspname, array_to_string(reloptions, '') AS relopts
+  FROM
+    pg_class INNER JOIN pg_namespace ns ON relnamespace = ns.oid
+), vacuum_settings AS (
+  SELECT
+    oid, relname, nspname,
+    CASE
+      WHEN relopts LIKE '%autovacuum_vacuum_threshold%'
+        THEN substring(relopts, '.*autovacuum_vacuum_threshold=([0-9.]+).*')::integer
+        ELSE current_setting('autovacuum_vacuum_threshold')::integer
+      END AS autovacuum_vacuum_threshold,
+    CASE
+      WHEN relopts LIKE '%autovacuum_vacuum_scale_factor%'
+        THEN substring(relopts, '.*autovacuum_vacuum_scale_factor=([0-9.]+).*')::real
+        ELSE current_setting('autovacuum_vacuum_scale_factor')::real
+      END AS autovacuum_vacuum_scale_factor
+  FROM
+    table_opts
+)
+SELECT
+  vacuum_settings.nspname AS schema,
+  vacuum_settings.relname AS table,
+  coalesce(to_char(psut.last_vacuum, 'YYYY-MM-DD HH24:MI'), '') AS last_vacuum,
+  coalesce(to_char(psut.last_autovacuum, 'YYYY-MM-DD HH24:MI'), '') AS last_autovacuum,
+  to_char(pg_class.reltuples, '9G999G999G999') AS rowcount,
+  to_char(psut.n_dead_tup, '9G999G999G999') AS dead_rowcount,
+  to_char(autovacuum_vacuum_threshold
+       + (autovacuum_vacuum_scale_factor::numeric * pg_class.reltuples), '9G999G999G999') AS autovacuum_threshold,
+  CASE
+    WHEN autovacuum_vacuum_threshold + (autovacuum_vacuum_scale_factor::numeric * pg_class.reltuples) < psut.n_dead_tup
+    THEN 'yes'
+    ELSE 'no'
+  END AS expect_autovacuum
+FROM
+  pg_stat_user_tables psut INNER JOIN pg_class ON psut.relid = pg_class.oid
+INNER JOIN vacuum_settings ON pg_class.oid = vacuum_settings.oid
+WHERE NOT vacuum_settings.nspname LIKE ANY($1)
+ORDER BY
+  case
+    when pg_class.reltuples = -1 then 1
+    else 0
+  end,
+  1`
diff --git a/internal/inspect/replication_slots/replication_slots.go b/internal/inspect/replication_slots/replication_slots.go
index 97408d6c..b66e7a0d 100644
--- a/internal/inspect/replication_slots/replication_slots.go
+++ b/internal/inspect/replication_slots/replication_slots.go
@@ -8,28 +8,15 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT
-  s.slot_name,
-  s.active,
-  COALESCE(r.state, 'N/A') as state,
-  CASE WHEN r.client_addr IS NULL
-     THEN 'N/A'
-     ELSE r.client_addr::text
-  END replication_client_address,
-  GREATEST(0, ROUND((redo_lsn-restart_lsn)/1024/1024/1024, 2)) as replication_lag_gb
-FROM pg_control_checkpoint(), pg_replication_slots s
-LEFT JOIN pg_stat_replication r ON (r.pid = s.active_pid);
-`
-
 type Result struct {
 	Slot_name                  string
-	Active                     string
+	Active                     bool
 	State                      string
 	Replication_client_address string
 	Replication_lag_gb         string
@@ -40,7 +27,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.REPLICATION_SLOTS_QUERY)
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
@@ -51,7 +38,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	// TODO: implement a markdown table marshaller
 	table := "|Name|Active|State|Replication Client Address|Replication Lag GB|\n|-|-|-|-|-|\n"
 	for _, r := range result {
-		table += fmt.Sprintf("|`%s`|`%v`|`%v`|`%v`|`%v`|\n", r.Slot_name, r.Active, r.State, r.Replication_client_address, r.Replication_lag_gb)
+		table += fmt.Sprintf("|`%s`|`%t`|`%s`|`%s`|`%s`|\n", r.Slot_name, r.Active, r.State, r.Replication_client_address, r.Replication_lag_gb)
 	}
 	return list.RenderTable(table)
 }
diff --git a/internal/inspect/role_connections/role_connections.go b/internal/inspect/role_connections/role_connections.go
index 0f5c92e8..b0a2aa1f 100644
--- a/internal/inspect/role_connections/role_connections.go
+++ b/internal/inspect/role_connections/role_connections.go
@@ -8,29 +8,12 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-select
-  rolname,
-  (
-    select
-      count(*)
-    from
-      pg_stat_activity
-    where
-      pg_roles.rolname = pg_stat_activity.usename
-  ) as active_connections,
-  case when rolconnlimit = -1 then current_setting('max_connections') :: int8
-       else rolconnlimit
-  end as connection_limit
-from
-  pg_roles
-order by 2 desc`
-
 type Result struct {
 	Rolname            string
 	Active_connections int
@@ -42,7 +25,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.ROLE_CONNECTIONS_QUERY)
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
diff --git a/internal/inspect/seq_scans/seq_scans.go b/internal/inspect/seq_scans/seq_scans.go
index e0235118..3cb4cf55 100644
--- a/internal/inspect/seq_scans/seq_scans.go
+++ b/internal/inspect/seq_scans/seq_scans.go
@@ -8,21 +8,16 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/db/reset"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT relname AS name,
-       seq_scan as count
-FROM
-  pg_stat_user_tables
-ORDER BY seq_scan DESC;`
-
 type Result struct {
 	Name  string
-	Count string
+	Count int64
 }
 
 func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
@@ -30,7 +25,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.SEQ_SCANS_QUERY, reset.LikeEscapeSchema(utils.InternalSchemas))
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
@@ -41,7 +36,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 
 	table := "|Name|Count|\n|-|-|\n"
 	for _, r := range result {
-		table += fmt.Sprintf("|`%s`|`%s`|\n", r.Name, r.Count)
+		table += fmt.Sprintf("|`%s`|`%d`|\n", r.Name, r.Count)
 	}
 	return list.RenderTable(table)
 }
diff --git a/internal/inspect/table_index_sizes/table_index_sizes.go b/internal/inspect/table_index_sizes/table_index_sizes.go
index 62905833..905ad3b5 100644
--- a/internal/inspect/table_index_sizes/table_index_sizes.go
+++ b/internal/inspect/table_index_sizes/table_index_sizes.go
@@ -8,21 +8,13 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/db/reset"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT c.relname AS table,
-  pg_size_pretty(pg_indexes_size(c.oid)) AS index_size
-FROM pg_class c
-LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
-WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
-AND n.nspname !~ '^pg_toast'
-AND c.relkind='r'
-ORDER BY pg_indexes_size(c.oid) DESC;`
-
 type Result struct {
 	Table      string
 	Index_size string
@@ -33,7 +25,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.TABLE_INDEX_SIZES_QUERY, reset.LikeEscapeSchema(utils.InternalSchemas))
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
diff --git a/internal/inspect/table_record_counts/table_record_counts.go b/internal/inspect/table_record_counts/table_record_counts.go
index ba204c84..72ca70de 100644
--- a/internal/inspect/table_record_counts/table_record_counts.go
+++ b/internal/inspect/table_record_counts/table_record_counts.go
@@ -8,23 +8,17 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/db/reset"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT
-  relname AS name,
-  n_live_tup AS estimated_count
-FROM
-  pg_stat_user_tables
-ORDER BY
-  n_live_tup DESC;`
-
 type Result struct {
+	Schema          string
 	Name            string
-	Estimated_count string
+	Estimated_count int64
 }
 
 func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
@@ -32,7 +26,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.TABLE_RECORD_COUNTS_QUERY, reset.LikeEscapeSchema(utils.PgSchemas))
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
@@ -41,9 +35,9 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 		return err
 	}
 
-	table := "|Name|Estimated count|\n|-|-|\n"
+	table := "Schema|Table|Estimated count|\n|-|-|-|\n"
 	for _, r := range result {
-		table += fmt.Sprintf("|`%s`|`%s`|\n", r.Name, r.Estimated_count)
+		table += fmt.Sprintf("|`%s`|`%s`|`%d`|\n", r.Schema, r.Name, r.Estimated_count)
 	}
 	return list.RenderTable(table)
 }
diff --git a/internal/inspect/table_sizes/table_sizes.go b/internal/inspect/table_sizes/table_sizes.go
index 579ba172..74c0396d 100644
--- a/internal/inspect/table_sizes/table_sizes.go
+++ b/internal/inspect/table_sizes/table_sizes.go
@@ -8,24 +8,17 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/db/reset"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT c.relname AS name,
-  pg_size_pretty(pg_table_size(c.oid)) AS size
-FROM pg_class c
-LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
-WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
-AND n.nspname !~ '^pg_toast'
-AND c.relkind='r'
-ORDER BY pg_table_size(c.oid) DESC;`
-
 type Result struct {
-	Name string
-	Size string
+	Schema string
+	Name   string
+	Size   string
 }
 
 func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
@@ -33,7 +26,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.TABLE_SIZES_QUERY, reset.LikeEscapeSchema(utils.PgSchemas))
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
@@ -42,9 +35,9 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 		return err
 	}
 
-	table := "|Name|size|\n|-|-|\n"
+	table := "Schema|Table|size|\n|-|-|-|\n"
 	for _, r := range result {
-		table += fmt.Sprintf("|`%s`|`%s`|\n", r.Name, r.Size)
+		table += fmt.Sprintf("|`%s`|`%s`|`%s`|\n", r.Schema, r.Name, r.Size)
 	}
 	return list.RenderTable(table)
 }
diff --git a/internal/inspect/total_index_size/total_index_size.go b/internal/inspect/total_index_size/total_index_size.go
index 38900177..73ee9e67 100644
--- a/internal/inspect/total_index_size/total_index_size.go
+++ b/internal/inspect/total_index_size/total_index_size.go
@@ -8,20 +8,13 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/db/reset"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT pg_size_pretty(sum(c.relpages::bigint*8192)::bigint) AS size
-FROM pg_class c
-LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
-WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
-AND n.nspname !~ '^pg_toast'
-AND c.relkind='i';
-`
-
 type Result struct {
 	Size string
 }
@@ -31,7 +24,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.TOTAL_INDEX_SIZE_QUERY, reset.LikeEscapeSchema(utils.InternalSchemas))
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
diff --git a/internal/inspect/total_table_sizes/total_table_sizes.go b/internal/inspect/total_table_sizes/total_table_sizes.go
index e47f90b6..8fd44195 100644
--- a/internal/inspect/total_table_sizes/total_table_sizes.go
+++ b/internal/inspect/total_table_sizes/total_table_sizes.go
@@ -8,25 +8,17 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/db/reset"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT c.relname AS name,
-  pg_size_pretty(pg_total_relation_size(c.oid)) AS size
-FROM pg_class c
-LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
-WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
-AND n.nspname !~ '^pg_toast'
-AND c.relkind='r'
-ORDER BY pg_total_relation_size(c.oid) DESC;
-`
-
 type Result struct {
-	Name string
-	Size string
+	Schema string
+	Name   string
+	Size   string
 }
 
 func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
@@ -34,7 +26,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.TOTAL_TABLE_SIZES_QUERY, reset.LikeEscapeSchema(utils.PgSchemas))
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
@@ -43,9 +35,9 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 		return err
 	}
 
-	table := "|Name|Size|\n|-|-|\n"
+	table := "Schema|Table|Size|\n|-|-|-|\n"
 	for _, r := range result {
-		table += fmt.Sprintf("|`%s`|`%s`|\n", r.Name, r.Size)
+		table += fmt.Sprintf("|`%s`|`%s`|`%s`|\n", r.Schema, r.Name, r.Size)
 	}
 	return list.RenderTable(table)
 }
diff --git a/internal/inspect/unused_indexes/unused_indexes.go b/internal/inspect/unused_indexes/unused_indexes.go
index 18fc06dc..ca0c4fef 100644
--- a/internal/inspect/unused_indexes/unused_indexes.go
+++ b/internal/inspect/unused_indexes/unused_indexes.go
@@ -8,28 +8,18 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/db/reset"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-SELECT
-  schemaname || '.' || relname AS table,
-  indexrelname AS index,
-  pg_size_pretty(pg_relation_size(i.indexrelid)) AS index_size,
-  idx_scan as index_scans
-FROM pg_stat_user_indexes ui
-JOIN pg_index i ON ui.indexrelid = i.indexrelid
-WHERE NOT indisunique AND idx_scan < 50 AND pg_relation_size(relid) > 5 * 8192
-ORDER BY pg_relation_size(i.indexrelid) / nullif(idx_scan, 0) DESC NULLS FIRST,
-pg_relation_size(i.indexrelid) DESC;`
-
 type Result struct {
 	Table       string
 	Index       string
 	Index_size  string
-	Index_scans string
+	Index_scans int64
 }
 
 func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
@@ -37,7 +27,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.UNUSED_INDEXES_QUERY, reset.LikeEscapeSchema(utils.InternalSchemas))
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
@@ -48,7 +38,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 
 	table := "|Table|Index|Index Size|Index Scans\n|-|-|-|-|\n"
 	for _, r := range result {
-		table += fmt.Sprintf("|`%s`|`%s`|`%s`|`%s`|\n", r.Table, r.Index, r.Index_size, r.Index_scans)
+		table += fmt.Sprintf("|`%s`|`%s`|`%s`|`%d`|\n", r.Table, r.Index, r.Index_size, r.Index_scans)
 	}
 	return list.RenderTable(table)
 }
diff --git a/internal/inspect/vacuum_stats/vacuum_stats.go b/internal/inspect/vacuum_stats/vacuum_stats.go
index 220990ed..cc98b6b0 100644
--- a/internal/inspect/vacuum_stats/vacuum_stats.go
+++ b/internal/inspect/vacuum_stats/vacuum_stats.go
@@ -9,57 +9,13 @@ import (
 	"github.com/jackc/pgconn"
 	"github.com/jackc/pgx/v4"
 	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/db/reset"
+	"github.com/supabase/cli/internal/inspect"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/pgxv5"
 )
 
-const QUERY = `
-WITH table_opts AS (
-  SELECT
-    pg_class.oid, relname, nspname, array_to_string(reloptions, '') AS relopts
-  FROM
-     pg_class INNER JOIN pg_namespace ns ON relnamespace = ns.oid
-), vacuum_settings AS (
-  SELECT
-    oid, relname, nspname,
-    CASE
-      WHEN relopts LIKE '%autovacuum_vacuum_threshold%'
-        THEN substring(relopts, '.*autovacuum_vacuum_threshold=([0-9.]+).*')::integer
-        ELSE current_setting('autovacuum_vacuum_threshold')::integer
-      END AS autovacuum_vacuum_threshold,
-    CASE
-      WHEN relopts LIKE '%autovacuum_vacuum_scale_factor%'
-        THEN substring(relopts, '.*autovacuum_vacuum_scale_factor=([0-9.]+).*')::real
-        ELSE current_setting('autovacuum_vacuum_scale_factor')::real
-      END AS autovacuum_vacuum_scale_factor
-  FROM
-    table_opts
-)
-SELECT
-  vacuum_settings.nspname AS schema,
-  vacuum_settings.relname AS table,
-  coalesce(to_char(psut.last_vacuum, 'YYYY-MM-DD HH24:MI'), '') AS last_vacuum,
-  coalesce(to_char(psut.last_autovacuum, 'YYYY-MM-DD HH24:MI'), '') AS last_autovacuum,
-  to_char(pg_class.reltuples, '9G999G999G999') AS rowcount,
-  to_char(psut.n_dead_tup, '9G999G999G999') AS dead_rowcount,
-  to_char(autovacuum_vacuum_threshold
-       + (autovacuum_vacuum_scale_factor::numeric * pg_class.reltuples), '9G999G999G999') AS autovacuum_threshold,
-  CASE
-    WHEN autovacuum_vacuum_threshold + (autovacuum_vacuum_scale_factor::numeric * pg_class.reltuples) < psut.n_dead_tup
-    THEN 'yes'
-    ELSE 'no'
-  END AS expect_autovacuum
-FROM
-  pg_stat_user_tables psut INNER JOIN pg_class ON psut.relid = pg_class.oid
-INNER JOIN vacuum_settings ON pg_class.oid = vacuum_settings.oid
-ORDER BY
-  case
-    when pg_class.reltuples = -1 then 1
-    else 0
-  end,
-  1`
-
 type Result struct {
 	Schema               string
 	Table                string
@@ -76,7 +32,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu
 	if err != nil {
 		return err
 	}
-	rows, err := conn.Query(ctx, QUERY)
+	rows, err := conn.Query(ctx, inspect.VACUUM_STATS_QUERY, reset.LikeEscapeSchema(utils.InternalSchemas))
 	if err != nil {
 		return errors.Errorf("failed to query rows: %w", err)
 	}
diff --git a/internal/migration/repair/repair.go b/internal/migration/repair/repair.go
index 36b7e8cd..714bc374 100644
--- a/internal/migration/repair/repair.go
+++ b/internal/migration/repair/repair.go
@@ -52,7 +52,10 @@ func Run(ctx context.Context, config pgconn.Config, version []string, status str
 	}
 	defer conn.Close(context.Background())
 	// Update migration history
-	return UpdateMigrationTable(ctx, conn, version, status, repairAll, fsys)
+	if err = UpdateMigrationTable(ctx, conn, version, status, repairAll, fsys); err == nil {
+		utils.CmdSuggestion = fmt.Sprintf("Run %s to show the updated migration history.", utils.Aqua("supabase migration list"))
+	}
+	return err
 }
 
 func UpdateMigrationTable(ctx context.Context, conn *pgx.Conn, version []string, status string, repairAll bool, fsys afero.Fs) error {
@@ -84,7 +87,6 @@ func UpdateMigrationTable(ctx context.Context, conn *pgx.Conn, version []string,
 	if !repairAll {
 		fmt.Fprintf(os.Stderr, "Repaired migration history: %v => %s\n", version, status)
 	}
-	utils.CmdSuggestion = fmt.Sprintf("Run %s to show the updated migration history.", utils.Aqua("supabase migration list"))
 	return nil
 }
 
diff --git a/internal/projects/create/create.go b/internal/projects/create/create.go
index 7e107500..c7d76f43 100644
--- a/internal/projects/create/create.go
+++ b/internal/projects/create/create.go
@@ -35,7 +35,7 @@ func Run(ctx context.Context, params api.CreateProjectBody, fsys afero.Fs) error
 	}
 
 	projectUrl := fmt.Sprintf("%s/project/%s", utils.GetSupabaseDashboardURL(), resp.JSON201.Id)
-	fmt.Printf("Created a new project %s at %s\n", utils.Aqua(resp.JSON201.Name), projectUrl)
+	fmt.Printf("Created a new project %s at %s\n", utils.Aqua(resp.JSON201.Name), utils.Bold(projectUrl))
 	return nil
 }
 
diff --git a/internal/start/start.go b/internal/start/start.go
index e25ed4c0..7f393a2b 100644
--- a/internal/start/start.go
+++ b/internal/start/start.go
@@ -404,6 +404,8 @@ EOF
 			fmt.Sprintf("GOTRUE_MAILER_SECURE_EMAIL_CHANGE_ENABLED=%v", utils.Config.Auth.Email.DoubleConfirmChanges),
 			fmt.Sprintf("GOTRUE_MAILER_AUTOCONFIRM=%v", !utils.Config.Auth.Email.EnableConfirmations),
 
+			fmt.Sprintf("GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED=%v", utils.Config.Auth.EnableAnonymousSignIns),
+
 			"GOTRUE_SMTP_HOST=" + utils.InbucketId,
 			"GOTRUE_SMTP_PORT=2500",
 			"GOTRUE_SMTP_ADMIN_EMAIL=admin@email.com",
@@ -850,7 +852,7 @@ EOF
 					"HOSTNAME=0.0.0.0",
 				},
 				Healthcheck: &container.HealthConfig{
-					Test:     []string{"CMD", "node", "-e", "require('http').get('http://127.0.0.1:3000/api/profile', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})"},
+					Test:     []string{"CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/profile', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})"},
 					Interval: 10 * time.Second,
 					Timeout:  2 * time.Second,
 					Retries:  3,
diff --git a/internal/utils/config.go b/internal/utils/config.go
index 92afdce7..5e36248b 100644
--- a/internal/utils/config.go
+++ b/internal/utils/config.go
@@ -317,10 +317,11 @@ type (
 		EnableManualLinking        bool `toml:"enable_manual_linking"`
 		Hook                       hook `toml:"hook"`
 
-		EnableSignup bool  `toml:"enable_signup"`
-		Email        email `toml:"email"`
-		Sms          sms   `toml:"sms"`
-		External     map[string]provider
+		EnableSignup           bool  `toml:"enable_signup"`
+		EnableAnonymousSignIns bool  `toml:"enable_anonymous_sign_ins"`
+		Email                  email `toml:"email"`
+		Sms                    sms   `toml:"sms"`
+		External               map[string]provider
 
 		// Custom secrets can be injected from .env file
 		JwtSecret      string `toml:"-" mapstructure:"jwt_secret"`
diff --git a/internal/utils/misc.go b/internal/utils/misc.go
index 58a13dfd..3876a0bc 100644
--- a/internal/utils/misc.go
+++ b/internal/utils/misc.go
@@ -34,13 +34,13 @@ const (
 	DifferImage      = "supabase/pgadmin-schema-diff:cli-0.0.5"
 	MigraImage       = "supabase/migra:3.0.1663481299"
 	PgmetaImage      = "supabase/postgres-meta:v0.80.0"
-	StudioImage      = "supabase/studio:20240326-5e5586d"
+	StudioImage      = "supabase/studio:20240408-6bf3b81"
 	ImageProxyImage  = "darthsim/imgproxy:v3.8.0"
 	EdgeRuntimeImage = "supabase/edge-runtime:v1.41.3"
 	VectorImage      = "timberio/vector:0.28.1-alpine"
 	PgbouncerImage   = "bitnami/pgbouncer:1.20.1-debian-11-r39"
 	PgProveImage     = "supabase/pg_prove:3.36"
-	GotrueImage      = "supabase/gotrue:v2.143.0"
+	GotrueImage      = "supabase/gotrue:v2.145.0"
 	RealtimeImage    = "supabase/realtime:v2.27.5"
 	StorageImage     = "supabase/storage-api:v0.46.4"
 	LogflareImage    = "supabase/logflare:1.4.0"
@@ -107,9 +107,11 @@ var (
 	ImageNamePattern   = regexp.MustCompile(`\/(.*):`)
 
 	// These schemas are ignored from db diff and db dump
-	SystemSchemas = []string{
+	PgSchemas = []string{
 		"information_schema",
 		"pg_*", // Wildcard pattern follows pg_dump
+	}
+	SystemSchemas = append([]string{
 		// Owned by extensions
 		"cron",
 		"graphql",
@@ -125,7 +127,7 @@ var (
 		"_timescaledb_*",
 		"topology",
 		"vault",
-	}
+	}, PgSchemas...)
 	InternalSchemas = append([]string{
 		"auth",
 		"extensions",
diff --git a/internal/utils/templates/init_config.toml b/internal/utils/templates/init_config.toml
index dbbadd06..a6f14032 100644
--- a/internal/utils/templates/init_config.toml
+++ b/internal/utils/templates/init_config.toml
@@ -83,6 +83,8 @@ enable_refresh_token_rotation = true
 refresh_token_reuse_interval = 10
 # Allow/disallow new user signups to your project.
 enable_signup = true
+# Allow/disallow anonymous sign-ins to your project.
+enable_anonymous_sign_ins = false
 # Allow/disallow testing manual linking of accounts
 enable_manual_linking = false
 
diff --git a/pkg/api/types.gen.go b/pkg/api/types.gen.go
index 911f7801..2ceaaa99 100644
--- a/pkg/api/types.gen.go
+++ b/pkg/api/types.gen.go
@@ -555,6 +555,9 @@ type CreateProjectBody struct {
 
 	// Region Region you want your server to reside in
 	Region CreateProjectBodyRegion `json:"region"`
+
+	// TemplateUrl Template URL used to create the project from the CLI.
+	TemplateUrl *string `json:"template_url,omitempty"`
 }
 
 // CreateProjectBodyPlan Subscription plan is now set on organization level and is ignored in this request


Test patch:
diff --git a/internal/bootstrap/bootstrap_test.go b/internal/bootstrap/bootstrap_test.go
index 34661e9d..6cf6eb6e 100644
--- a/internal/bootstrap/bootstrap_test.go
+++ b/internal/bootstrap/bootstrap_test.go
@@ -19,29 +19,28 @@ func TestSuggestAppStart(t *testing.T) {
 		cwd, err := os.Getwd()
 		require.NoError(t, err)
 		// Run test
-		suggestion := suggestAppStart(cwd)
+		suggestion := suggestAppStart(cwd, "npm ci && npm run dev")
 		// Check error
-		assert.Equal(t, "To start your app:\n  npm ci\n  npm run dev", suggestion)
+		assert.Equal(t, "To start your app:\n  npm ci && npm run dev", suggestion)
 	})
 
 	t.Run("suggest cd", func(t *testing.T) {
 		cwd, err := os.Getwd()
 		require.NoError(t, err)
 		// Run test
-		suggestion := suggestAppStart(filepath.Dir(cwd))
+		suggestion := suggestAppStart(filepath.Dir(cwd), "npm ci && npm run dev")
 		// Check error
 		expected := "To start your app:"
 		expected += "\n  cd " + filepath.Base(cwd)
-		expected += "\n  npm ci"
-		expected += "\n  npm run dev"
+		expected += "\n  npm ci && npm run dev"
 		assert.Equal(t, expected, suggestion)
 	})
 
 	t.Run("ignore relative path", func(t *testing.T) {
 		// Run test
-		suggestion := suggestAppStart(".")
+		suggestion := suggestAppStart(".", "supabase start")
 		// Check error
-		assert.Equal(t, "To start your app:\n  npm ci\n  npm run dev", suggestion)
+		assert.Equal(t, "To start your app:\n  supabase start", suggestion)
 	})
 }
 
diff --git a/internal/db/diff/diff_test.go b/internal/db/diff/diff_test.go
index 00d019d4..5d714315 100644
--- a/internal/db/diff/diff_test.go
+++ b/internal/db/diff/diff_test.go
@@ -43,8 +43,6 @@ var escapedSchemas = []string{
 	`\_analytics`,
 	`supabase\_functions`,
 	`supabase\_migrations`,
-	`information\_schema`,
-	`pg\_%`,
 	"cron",
 	"graphql",
 	`graphql\_public`,
@@ -59,6 +57,8 @@ var escapedSchemas = []string{
 	`\_timescaledb\_%`,
 	"topology",
 	"vault",
+	`information\_schema`,
+	`pg\_%`,
 }
 
 func TestRun(t *testing.T) {
diff --git a/internal/db/pull/pull_test.go b/internal/db/pull/pull_test.go
index 62c49ff9..fba4fa1a 100644
--- a/internal/db/pull/pull_test.go
+++ b/internal/db/pull/pull_test.go
@@ -39,8 +39,6 @@ var escapedSchemas = []string{
 	`\_analytics`,
 	`supabase\_functions`,
 	`supabase\_migrations`,
-	`information\_schema`,
-	`pg\_%`,
 	"cron",
 	"graphql",
 	`graphql\_public`,
@@ -55,6 +53,8 @@ var escapedSchemas = []string{
 	`\_timescaledb\_%`,
 	"topology",
 	"vault",
+	`information\_schema`,
+	`pg\_%`,
 }
 
 func TestPullCommand(t *testing.T) {
diff --git a/internal/db/reset/reset_test.go b/internal/db/reset/reset_test.go
index 3b91a344..cbeecb93 100644
--- a/internal/db/reset/reset_test.go
+++ b/internal/db/reset/reset_test.go
@@ -302,8 +302,6 @@ var escapedSchemas = []string{
 	"storage",
 	`\_analytics`,
 	`supabase\_functions`,
-	`information\_schema`,
-	`pg\_%`,
 	"cron",
 	"graphql",
 	`graphql\_public`,
@@ -318,6 +316,8 @@ var escapedSchemas = []string{
 	`\_timescaledb\_%`,
 	"topology",
 	"vault",
+	`information\_schema`,
+	`pg\_%`,
 }
 
 func TestResetRemote(t *testing.T) {