Using Supabase as a database and image store with Strapi CMS.
Tags: webdev, javascript, database
Published: 2023-10-01 17:03:46

I love the idea of a headless CMS to maintain my own personal API. The goal is to have a central source for all your data, blog posts, link lists, even job history data for a resume, small blurbs, summaries, and I have one for a list of github projects.

I fell in love with Strapi a couple months back and was interested in revisiting the project I created locally. What's cool about it is you can create custom content types with their own fields and you get an API from it. 

I also love Supabase I think it's a great service with a ton of useful parts, it's a full postgres database, and an API layer too, so you don't even need to use Strapi's api if you wanted to. Strapi could just be used to write data to Supabase. Strapi also supports media uploads, and rather then using AWS or GCP I liked the idea of everything being under one service.

Here's the setup on how to use Supabase as both your database and media storage. 

Once you have a strapi project setup you need to simply set your env vars to your supabase credentials that's the easy part then you're interacting with supabase directly.

To get the image store to work I had a bunch of issues. I found a module on github https://github.com/crubier/strapi-provider-upload-supabase I ended up going with a more up to date fork `https://github.com/arkivedao/strapi-provider-upload-supabase` you can npm install this by using the github url. 

Create a new file `config/plugins.ts`:

```ts
export default ({ env }) => ({
  upload: {
    config: {
      provider: "strapi-provider-upload-supabase",
      providerOptions: {
        apiUrl: env('SUPABASE_API_URL'),
        apiKey: env('SUPABASE_API_KEY'),
        bucket: env('SUPABASE_BUCKET'),
        directory: env('SUPABASE_DIRECTORY'),
      }
    },
  }, 
})
```

Once I set this up I was getting this error:

```json
{
  "statusCode": "401",
  "error": "Invalid JWT",
  "message": "new row violates row-level security policy for table \"objects\""
}
```

I had to turn of RLS for the object store in order to get it to work using the answer found here: https://stackoverflow.com/questions/72861584/supabase-bucket-policy-to-insert-file-not-working

Then to get thumbnails to work locally I needed my `config/middlewares.ts` file to look like this:

```ts
export default ({ env }) => [
  'strapi::errors',
  {
    name: 'strapi::security',
    config: {
      contentSecurityPolicy: {
        useDefaults: true,
        directives: {
          'connect-src': ["'self'", 'https:', 'http:'],
          'img-src': [
            "'self'",
            'data:',
            'blob:',
            'res.cloudinary.com', // cloudinary images
            'lh3.googleusercontent.com', // google avatars
            'platform-lookaside.fbsbx.com', // facebook avatars
            'dl.airtable.com', // strapi marketplace,
            "market-assets.strapi.io",
            env('SUPABASE_API_URL'),
          ],
          'media-src': ["'self'", 'data:', 'blob:', env('SUPABASE_API_URL')],
          upgradeInsecureRequests: null,
        },
      },
    },
  },
  'strapi::cors',
  'strapi::poweredBy',
  'strapi::logger',
  'strapi::query',
  'strapi::body',
  'strapi::session',
  'strapi::favicon',
  'strapi::public',
];
```

And it worked. Now I have a Strapi server wired up to use Supabase! Hope this helps someone out there.