Create Midjourney Alternative with Supabase and Hugging Face in Minutes

I'm a self-taught web developer. I occasionally post summaries of my projects and what I learned from them. Thanks for tuning in! ❤
Search for a command to run...

I'm a self-taught web developer. I occasionally post summaries of my projects and what I learned from them. Thanks for tuning in! ❤
Is the huggingface access token rate limited
If I understand it correctly, only for heavy use cases, aka don't send a ton of requests at once
Every beginner who wants to get into development must start somewhere. Although every beginner has a certain goal in mind like “getting a job in tech”, there are multiple options on where to start. Whether it's a bootcamp, Udemy course, university or...

In one of my previous blog posts, I demonstrated how to build a MidJourney alternative using Supabase and Hugging Face in a few minutes. This is great for personal use, but what are you going to do with these generated images? And what if you want to...

This blog post is all about creating a Multi-User Note App with Next.js and Supabase. We'll walk through structuring a dynamic database, and building cool interactive features for a smooth note-taking experience. Join us on this journey to build a sp...

Artificial intelligence (AI) became very trendy in the last half a year. With the introduction of ChatGPT, OpenAI took the spotlight in the AI space. This wonders nobody, as apart from offering this useful tool to normal folks, OpenAI offers many AI ...

There is no doubt that Midjourney is currently the leading tool for AI image generation out there. However, people who don't generate AI images daily may find the cost of their subscription a bit too much. So you can seek alternatives, but that's not what real developers do. We build our very own alternatives! Luckily, using Supabase Storage, Supabase Edge Functions and Hugging Face we can build an alternative to Midjourney in minutes. Let me show you how.
1) Open your Supabase project dashboard or create a new project.
2) Create a new bucket called images.
3) Create a new database table called image_generation. You can make use of Supabase's integrated AI assistant by passing the prompt: “New table called image generation with id uuid, input text”. This is cool to get the proper SQL structure in place, you will probably need to adjust some labels and attributes, but that's what my SQL query looked like in the end.
create table
image_generation (
id uuid primary key default gen_random_uuid (),
input text,
);
4) Set up a directory for all of your future edge functions under /supabase
5) Install Supabase CLI if you haven't done it yet
6) Create a new folder under /supabase/huggingface-image-generation
7) Inside that folder, create index.ts (this is where our code is going) and generate TypeScript types from the remote database using the following command (replace your-project-ref with your project reference).
supabase gen types typescript --project-id=your-project-ref --schema=storage,public > ./types.ts
Sign up on Hugging Face if you haven't done it yet. Generate a new Access Token under Settings/Access Token. Under Edge Function/Manage Secrets on Supabase add a new secret HUGGINGFACE_ACCESS_TOKEN and paste your secret there. As you can see, Supabase has already taken care of other secrets we will need in our application.

First, we import all Deno modules we will need in our application, followed up by declaring our hf constant we will use to access Hugging Face models later.
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
import { HfInference } from 'https://esm.sh/@huggingface/inference@2.3.2'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.7.1'
import { Database } from './types.ts'
const hf = new HfInference(Deno.env.get('HUGGINGFACE_ACCESS_TOKEN'))
Next, we declare the interface of our webhook payload.
type inputRecord = Database['public']['Tables']['image_generation']['Row']
interface WebhookPayload {
type: 'INSERT' | 'UPDATE' | 'DELETE'
table: string
record: inputRecord
schema: 'public'
old_record: null | inputRecord
}
Now let's get the input from our payload and set up the Supabase Client to interact with our database.
serve(async (req) => {
const payload: WebhookPayload = await req.json()
const inputRecord = payload.record
const supabaseAdminClient = createClient<Database>(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
)
/* ... */
Let's generate the image using the model stabilityai/stable-diffusion-2. Feel free to try out other models later on, Hugging Face has a lot of them.
/* ... */
const imgDesc = await hf.textToImage({
inputs: inputRecord.input,
model: 'stabilityai/stable-diffusion-2',
parameters: {
negative_prompt: 'blurry',
}
})
/* ... */
In the end, we upload the image to Supabase Storage together with inputRecord.id, so we will have a reference to the input. Finally, we return a response. Our code looks in the end like this.
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
import { HfInference } from 'https://esm.sh/@huggingface/inference@2.3.2'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.7.1'
import { Database } from './types.ts'
const hf = new HfInference(Deno.env.get('HUGGINGFACE_ACCESS_TOKEN'))
// Input WebHook
type inputRecord = Database['public']['Tables']['image_generation']['Row']
interface WebhookPayload {
type: 'INSERT' | 'UPDATE' | 'DELETE'
table: string
record: inputRecord
schema: 'public'
old_record: null | inputRecord
}
// Start the server
serve(async (req) => {
const payload: WebhookPayload = await req.json()
const inputRecord = payload.record
const supabaseAdminClient = createClient<Database>(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
)
// Generate the image using Hugging Face's API
const imgDesc = await hf.textToImage({
inputs: inputRecord.input,
model: 'stabilityai/stable-diffusion-2',
parameters: {
negative_prompt: 'blurry',
}
})
// Upload the image to Supabase Storage
const {data, error} = await supabaseAdminClient
.storage
.from('images')
.upload(inputRecord.id, imgDesc, {
cacheControl: '3600',
upsert: true
})
if (error) console.log(error)
if (data) console.log(data)
return new Response('ok')
})
To see our edge function in action, we have to deploy it to Supabase. For that, we run the following command.
supabase functions deploy huggingface-image-generator
Last but not least, we have to set up the webhook we referenced in our code.

Now that it's done. Here's the demo of how it works. Sorry for the quality, I recorded it on a toaster.
Thanks for reading! ❤️ This article is part of the AI Content Storm by Supabase. If you want to be the first one to see my next article, follow me on Hashnode and Twitter!