DEV Community

Thomas Reggi
Thomas Reggi

Posted on • Updated on

Using Supabase as a database and image store with Strapi CMS.

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 I ended up going with a more up to date fork you can npm install this by using the github url.

Create a new file config/plugins.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'),
Enter fullscreen mode Exit fullscreen mode

Once I set this up I was getting this error:

  "statusCode": "401",
  "error": "Invalid JWT",
  "message": "new row violates row-level security policy for table \"objects\""
Enter fullscreen mode Exit fullscreen mode

I had to turn of RLS for the object store in order to get it to work using the answer found here:

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

export default ({ env }) => [
    name: 'strapi::security',
    config: {
      contentSecurityPolicy: {
        useDefaults: true,
        directives: {
          'connect-src': ["'self'", 'https:', 'http:'],
          'img-src': [
            '', // cloudinary images
            '', // google avatars
            '', // facebook avatars
            '', // strapi marketplace,
          'media-src': ["'self'", 'data:', 'blob:', env('SUPABASE_API_URL')],
          upgradeInsecureRequests: null,
Enter fullscreen mode Exit fullscreen mode

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

Top comments (5)

drimescodes profile image

For me I wanted to serve the images straight from cloudinary
Like the images would be saved on cloudinary instead of supabase directly cause cloudinary has more space limit, but somehow somehow, the images aren't showing in the frontend and not also showing in supabase.


Image description

my middleware.js

Image description

PS:This is my first time using strapi

czapata08 profile image
Carlos Zapata

Thanks for the article, I'm also working with strapi and supabase. I'm curious to know which strapi and node version are you running?

reggi profile image
Thomas Reggi

Node.js v18.17.1 / "@strapi/strapi": "4.14.0",

czapata08 profile image
Carlos Zapata • Edited

Awesome man, I'm still trying to hook it up to my storage. I have set the policy but I'm encountering error code 500 "JWT Malformed". Any recommendations on setting up the policies?

Thread Thread
reggi profile image
Thomas Reggi

I had to remove row level policies for the object store check the stack overflow link for deets